diff --git a/atst/domain/csp/reports.py b/atst/domain/csp/reports.py index fd498227..514b05c9 100644 --- a/atst/domain/csp/reports.py +++ b/atst/domain/csp/reports.py @@ -225,8 +225,6 @@ class MockReportingProvider(ReportingInterface): def get_budget(self, portfolio): if portfolio.name in self.REPORT_FIXTURE_MAP: return self.REPORT_FIXTURE_MAP[portfolio.name]["budget"] - elif portfolio.request and portfolio.legacy_task_order: - return portfolio.legacy_task_order.budget return 0 def get_total_spending(self, portfolio): diff --git a/atst/models/__init__.py b/atst/models/__init__.py index 32f7144a..d4d0e8cc 100644 --- a/atst/models/__init__.py +++ b/atst/models/__init__.py @@ -2,8 +2,6 @@ from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() -from .request import Request -from .request_status_event import RequestStatusEvent from .permissions import Permissions from .role import Role from .user import User @@ -14,9 +12,6 @@ from .portfolio import Portfolio from .application import Application from .environment import Environment from .attachment import Attachment -from .request_revision import RequestRevision -from .request_review import RequestReview -from .request_internal_comment import RequestInternalComment from .audit_event import AuditEvent from .invitation import Invitation from .task_order import TaskOrder diff --git a/atst/models/audit_event.py b/atst/models/audit_event.py index c705ab1d..0e46b086 100644 --- a/atst/models/audit_event.py +++ b/atst/models/audit_event.py @@ -17,9 +17,6 @@ class AuditEvent(Base, TimestampsMixin): portfolio_id = Column(UUID(as_uuid=True), ForeignKey("portfolios.id"), index=True) portfolio = relationship("Portfolio", backref="audit_events") - request_id = Column(UUID(as_uuid=True), ForeignKey("requests.id"), index=True) - request = relationship("Request", backref="audit_events") - changed_state = Column(JSONB()) event_details = Column(JSONB()) diff --git a/atst/models/mixins/auditable.py b/atst/models/mixins/auditable.py index 5424cc03..86ada487 100644 --- a/atst/models/mixins/auditable.py +++ b/atst/models/mixins/auditable.py @@ -14,7 +14,6 @@ class AuditableMixin(object): def create_audit_event(connection, resource, action): user_id = getattr_path(g, "current_user.id") portfolio_id = resource.portfolio_id - request_id = resource.request_id resource_type = resource.resource_type display_name = resource.displayname event_details = resource.event_details @@ -24,7 +23,6 @@ class AuditableMixin(object): audit_event = AuditEvent( user_id=user_id, portfolio_id=portfolio_id, - request_id=request_id, resource_type=resource_type, resource_id=resource.id, display_name=display_name, @@ -91,10 +89,6 @@ class AuditableMixin(object): def portfolio_id(self): return None - @property - def request_id(self): - return None - @property def displayname(self): return None diff --git a/atst/models/portfolio.py b/atst/models/portfolio.py index da7e8301..68b5710b 100644 --- a/atst/models/portfolio.py +++ b/atst/models/portfolio.py @@ -13,7 +13,6 @@ class Portfolio(Base, mixins.TimestampsMixin, mixins.AuditableMixin): id = types.Id() name = Column(String) - request_id = Column(ForeignKey("requests.id"), nullable=True) applications = relationship("Application", back_populates="portfolio") roles = relationship("PortfolioRole") @@ -35,10 +34,6 @@ class Portfolio(Base, mixins.TimestampsMixin, mixins.AuditableMixin): def user_count(self): return len(self.members) - @property - def legacy_task_order(self): - return self.request.legacy_task_order if self.request else None - @property def members(self): return ( @@ -60,6 +55,6 @@ class Portfolio(Base, mixins.TimestampsMixin, mixins.AuditableMixin): return self.id def __repr__(self): - return "".format( - self.name, self.request_id, self.user_count, self.id + return "".format( + self.name, self.user_count, self.id ) diff --git a/atst/models/request.py b/atst/models/request.py deleted file mode 100644 index 68243468..00000000 --- a/atst/models/request.py +++ /dev/null @@ -1,256 +0,0 @@ -from sqlalchemy import Column, func, ForeignKey -from sqlalchemy.types import DateTime -from sqlalchemy.orm import relationship - -from atst.models import Base, types, mixins -from atst.models.request_status_event import RequestStatus -from atst.utils import first_or_none -from atst.models.request_revision import RequestRevision -from atst.models.legacy_task_order import Source as TaskOrderSource - - -def map_properties_to_dict(properties, instance): - return { - field: getattr(instance, field) - for field in properties - if getattr(instance, field) is not None - } - - -def update_dict_with_properties(instance, body, top_level_key, properties): - new_properties = map_properties_to_dict(properties, instance) - if new_properties: - body[top_level_key] = new_properties - - return body - - -class Request(Base, mixins.TimestampsMixin, mixins.AuditableMixin): - __tablename__ = "requests" - - id = types.Id() - time_created = Column(DateTime(timezone=True), server_default=func.now()) - status_events = relationship( - "RequestStatusEvent", backref="request", order_by="RequestStatusEvent.sequence" - ) - - portfolio = relationship("Portfolio", uselist=False, backref="request") - - user_id = Column(ForeignKey("users.id"), nullable=False) - creator = relationship("User", backref="owned_requests") - - legacy_task_order_id = Column(ForeignKey("legacy_task_orders.id")) - legacy_task_order = relationship("LegacyTaskOrder") - - revisions = relationship( - "RequestRevision", back_populates="request", order_by="RequestRevision.sequence" - ) - - internal_comments = relationship("RequestInternalComment") - - @property - def latest_revision(self): - if self.revisions: - return self.revisions[-1] - - else: - return RequestRevision(request=self) - - PRIMARY_POC_FIELDS = ["am_poc", "dodid_poc", "email_poc", "fname_poc", "lname_poc"] - DETAILS_OF_USE_FIELDS = [ - "jedi_usage", - "start_date", - "cloud_native", - "dollar_value", - "dod_component", - "data_transfers", - "expected_completion_date", - "jedi_migration", - "num_software_systems", - "number_user_sessions", - "average_daily_traffic", - "engineering_assessment", - "technical_support_team", - "estimated_monthly_spend", - "average_daily_traffic_gb", - "rationalization_software_systems", - "organization_providing_assistance", - "name", - ] - INFORMATION_ABOUT_YOU_FIELDS = [ - "citizenship", - "designation", - "phone_number", - "phone_ext", - "email_request", - "fname_request", - "lname_request", - "service_branch", - "date_latest_training", - ] - FINANCIAL_VERIFICATION_FIELDS = [ - "pe_id", - "task_order_number", - "fname_co", - "lname_co", - "email_co", - "office_co", - "fname_cor", - "lname_cor", - "email_cor", - "office_cor", - "uii_ids", - "treasury_code", - "ba_code", - ] - - @property - def body(self): - current = self.latest_revision - body = {} - for top_level_key, properties in [ - ("primary_poc", Request.PRIMARY_POC_FIELDS), - ("details_of_use", Request.DETAILS_OF_USE_FIELDS), - ("information_about_you", Request.INFORMATION_ABOUT_YOU_FIELDS), - ("financial_verification", Request.FINANCIAL_VERIFICATION_FIELDS), - ]: - body = update_dict_with_properties(current, body, top_level_key, properties) - - return body - - @property - def latest_status(self): - return self.status_events[-1] if self.status_events else None - - @property - def status(self): - return self.latest_status.new_status if self.latest_status else None - - @property - def status_displayname(self): - return self.latest_status.displayname - - @property - def annual_spend(self): - monthly = self.latest_revision.estimated_monthly_spend or 0 - return monthly * 12 - - @property - def financial_verification(self): - return self.body.get("financial_verification", {}) - - @property - def is_financially_verified(self): - if self.legacy_task_order: - return self.legacy_task_order.verified - return False - - @property - def last_submission_timestamp(self): - def _is_submission(status_event): - return status_event.new_status == RequestStatus.SUBMITTED - - last_submission = first_or_none(_is_submission, reversed(self.status_events)) - if last_submission: - return last_submission.time_created - return None - - @property - def action_required_by(self): - return { - RequestStatus.PENDING_FINANCIAL_VERIFICATION: "mission_owner", - RequestStatus.CHANGES_REQUESTED: "mission_owner", - RequestStatus.CHANGES_REQUESTED_TO_FINVER: "mission_owner", - RequestStatus.PENDING_CCPO_APPROVAL: "ccpo", - RequestStatus.PENDING_CCPO_ACCEPTANCE: "ccpo", - }.get(self.status) - - @property - def reviews(self): - return [status.review for status in self.status_events if status.review] - - @property - def is_pending_financial_verification(self): - return self.status == RequestStatus.PENDING_FINANCIAL_VERIFICATION - - @property - def is_pending_financial_verification_changes(self): - return self.status == RequestStatus.CHANGES_REQUESTED_TO_FINVER - - @property - def is_pending_ccpo_acceptance(self): - return self.status == RequestStatus.PENDING_CCPO_ACCEPTANCE - - @property - def is_pending_ccpo_approval(self): - return self.status == RequestStatus.PENDING_CCPO_APPROVAL - - @property - def is_pending_ccpo_action(self): - return self.is_pending_ccpo_acceptance or self.is_pending_ccpo_approval - - @property - def is_approved(self): - return self.status == RequestStatus.APPROVED - - @property - def review_comment(self): - if ( - self.status == RequestStatus.CHANGES_REQUESTED - or self.status == RequestStatus.CHANGES_REQUESTED_TO_FINVER - ): - review = self.latest_status.review - if review: # pragma: no branch - return review.comment - - @property - def has_financial_data(self): - return ( - self.is_pending_ccpo_approval - or self.is_pending_financial_verification_changes - or self.is_approved - ) and self.legacy_task_order - - @property - def displayname(self): - return self.latest_revision.name or self.id - - @property - def contracting_officer_full_name(self): - if self.latest_revision.fname_co: - return "{} {}".format( - self.latest_revision.fname_co, self.latest_revision.lname_co - ) - - @property - def contracting_officer_email(self): - return self.latest_revision.email_co - - @property - def pe_number(self): - return self.body.get("financial_verification", {}).get("pe_id") - - @property - def has_manual_task_order(self): - return ( - self.legacy_task_order.source == TaskOrderSource.MANUAL - if self.legacy_task_order is not None - else None - ) - - @property - def last_finver_draft_saved_at(self): - if self.latest_revision.any_finver_fields_saved: - return self.latest_revision.time_updated - else: - return None - - def __repr__(self): - return "".format( - self.status_displayname, - self.displayname, - self.creator.full_name, - self.is_approved, - self.time_created, - self.id, - ) diff --git a/atst/models/request_internal_comment.py b/atst/models/request_internal_comment.py deleted file mode 100644 index 14d9a298..00000000 --- a/atst/models/request_internal_comment.py +++ /dev/null @@ -1,22 +0,0 @@ -from sqlalchemy import Column, String, ForeignKey -from sqlalchemy.orm import relationship - -from atst.models import Base, types, mixins - - -class RequestInternalComment(Base, mixins.TimestampsMixin): - __tablename__ = "request_internal_comments" - - id = types.Id() - text = Column(String(), nullable=False) - - user_id = Column(ForeignKey("users.id"), nullable=False) - user = relationship("User") - - request_id = Column(ForeignKey("requests.id", ondelete="CASCADE"), nullable=False) - request = relationship("Request") - - def __repr__(self): # pragma: no cover - return "".format( - self.text, self.user.full_name, self.request_id, self.id - ) diff --git a/atst/models/request_review.py b/atst/models/request_review.py deleted file mode 100644 index f45fdfb7..00000000 --- a/atst/models/request_review.py +++ /dev/null @@ -1,43 +0,0 @@ -from sqlalchemy import Column, String, ForeignKey -from sqlalchemy.orm import relationship - -from atst.models import Base, mixins, types - - -class RequestReview(Base, mixins.TimestampsMixin, mixins.AuditableMixin): - __tablename__ = "request_reviews" - - id = types.Id() - status = relationship("RequestStatusEvent", uselist=False, back_populates="review") - - user_id = Column(ForeignKey("users.id")) - reviewer = relationship("User") - - comment = Column(String) - fname_mao = Column(String) - lname_mao = Column(String) - email_mao = Column(String) - phone_mao = Column(String) - phone_ext_mao = Column(String) - fname_ccpo = Column(String) - lname_ccpo = Column(String) - - @property - def full_name_reviewer(self): - if self.reviewer: - return self.reviewer.full_name - else: - return "System" - - @property - def full_name_mao(self): - return "{} {}".format(self.fname_mao, self.lname_mao) - - @property - def full_name_ccpo(self): - return "{} {}".format(self.fname_ccpo, self.lname_ccpo) - - def __repr__(self): - return "".format( - self.status.log_name, self.comment, self.full_name_reviewer, self.id - ) diff --git a/atst/models/request_revision.py b/atst/models/request_revision.py deleted file mode 100644 index 29c4e9b3..00000000 --- a/atst/models/request_revision.py +++ /dev/null @@ -1,106 +0,0 @@ -from sqlalchemy import ( - Column, - ForeignKey, - String, - Boolean, - Integer, - Date, - BigInteger, - Sequence, -) -from sqlalchemy.orm import relationship -from sqlalchemy.dialects.postgresql import ARRAY - -from atst.models import Base -from atst.models import mixins -from atst.models.types import Id - - -class RequestRevision(Base, mixins.TimestampsMixin, mixins.AuditableMixin): - __tablename__ = "request_revisions" - - id = Id() - request_id = Column(ForeignKey("requests.id"), nullable=False) - request = relationship("Request", back_populates="revisions") - sequence = Column( - BigInteger, Sequence("request_revisions_sequence_seq"), nullable=False - ) - - # primary_poc - am_poc = Column(Boolean) - dodid_poc = Column(String) - email_poc = Column(String) - fname_poc = Column(String) - lname_poc = Column(String) - - # details_of_use - jedi_usage = Column(String) - start_date = Column(Date) - cloud_native = Column(String) - dollar_value = Column(Integer) - dod_component = Column(String) - data_transfers = Column(String) - expected_completion_date = Column(String) - jedi_migration = Column(String) - num_software_systems = Column(Integer) - number_user_sessions = Column(Integer) - average_daily_traffic = Column(Integer) - engineering_assessment = Column(String) - technical_support_team = Column(String) - estimated_monthly_spend = Column(Integer) - average_daily_traffic_gb = Column(Integer) - rationalization_software_systems = Column(String) - organization_providing_assistance = Column(String) - name = Column(String) - - # information_about_you - citizenship = Column(String) - designation = Column(String) - phone_number = Column(String) - phone_ext = Column(String) - email_request = Column(String) - fname_request = Column(String) - lname_request = Column(String) - service_branch = Column(String) - date_latest_training = Column(Date) - - # financial_verification - pe_id = Column(String) - task_order_number = Column(String) - fname_co = Column(String) - lname_co = Column(String) - email_co = Column(String) - office_co = Column(String) - fname_cor = Column(String) - lname_cor = Column(String) - email_cor = Column(String) - office_cor = Column(String) - uii_ids = Column(ARRAY(String)) - treasury_code = Column(String) - ba_code = Column(String) - - def __repr__(self): # pragma: no cover - return "".format( - self.request_id, self.id - ) - - @property - def any_finver_fields_saved(self): - return any( - getattr(self, n, None) - for n in [ - "pe_id", - "task_order_number", - "fname_co", - "lname_co", - "email_co", - "office_co", - "fname_cor", - "lname_cor", - "email_cor", - "office_cor", - "uii_ids", - "treasury_code", - "ba_code", - ] - ) diff --git a/atst/models/request_status_event.py b/atst/models/request_status_event.py deleted file mode 100644 index e3367951..00000000 --- a/atst/models/request_status_event.py +++ /dev/null @@ -1,62 +0,0 @@ -from enum import Enum -from sqlalchemy import Column, ForeignKey, Enum as SQLAEnum -from sqlalchemy.orm import relationship -from sqlalchemy.types import BigInteger -from sqlalchemy.schema import Sequence -from sqlalchemy.dialects.postgresql import UUID - -from atst.models import Base, mixins -from atst.models.types import Id - - -class RequestStatus(Enum): - STARTED = "Started" - SUBMITTED = "Submitted" - PENDING_FINANCIAL_VERIFICATION = "Pending Financial Verification" - PENDING_CCPO_ACCEPTANCE = "Pending CCPO Acceptance" - PENDING_CCPO_APPROVAL = "Pending CCPO Approval" - CHANGES_REQUESTED = "Changes Requested" - CHANGES_REQUESTED_TO_FINVER = "Change Requested to Financial Verification" - APPROVED = "Approved" - EXPIRED = "Expired" - DELETED = "Deleted" - - -class RequestStatusEvent(Base, mixins.TimestampsMixin, mixins.AuditableMixin): - __tablename__ = "request_status_events" - - id = Id() - new_status = Column(SQLAEnum(RequestStatus, native_enum=False)) - request_id = Column( - UUID(as_uuid=True), - ForeignKey("requests.id", ondelete="CASCADE"), - nullable=False, - ) - sequence = Column( - BigInteger, Sequence("request_status_events_sequence_seq"), nullable=False - ) - request_revision_id = Column(ForeignKey("request_revisions.id"), nullable=False) - revision = relationship("RequestRevision") - - request_review_id = Column(ForeignKey("request_reviews.id"), nullable=True) - review = relationship("RequestReview", back_populates="status") - - @property - def displayname(self): - return self.new_status.value if self.new_status else None - - @property - def log_name(self): - if self.new_status == RequestStatus.CHANGES_REQUESTED: - return "Denied" - if self.new_status == RequestStatus.CHANGES_REQUESTED_TO_FINVER: - return "Denied" - elif self.new_status == RequestStatus.PENDING_FINANCIAL_VERIFICATION: - return "Accepted" - else: - return self.displayname - - def __repr__(self): - return "".format( - self.log_name, self.request_id, self.id - ) diff --git a/templates/portfolios/index.html b/templates/portfolios/index.html index de713653..610658b7 100644 --- a/templates/portfolios/index.html +++ b/templates/portfolios/index.html @@ -6,7 +6,6 @@ Portfolio Name - Task Order Users @@ -16,9 +15,6 @@ {{ portfolio.name }}
- - #{{ portfolio.legacy_task_order.number }} - {{ portfolio.user_count }}Users diff --git a/tests/domain/test_applications.py b/tests/domain/test_applications.py index 9bc792d9..5ac13cde 100644 --- a/tests/domain/test_applications.py +++ b/tests/domain/test_applications.py @@ -1,11 +1,10 @@ from atst.domain.applications import Applications -from tests.factories import RequestFactory, UserFactory, PortfolioFactory +from tests.factories import UserFactory, PortfolioFactory from atst.domain.portfolios import Portfolios def test_create_application_with_multiple_environments(): - request = RequestFactory.create() - portfolio = Portfolios.create_from_request(request) + portfolio = PortfolioFactory.create() application = Applications.create( portfolio.owner, portfolio, "My Test Application", "Test", ["dev", "prod"] ) diff --git a/tests/domain/test_portfolios.py b/tests/domain/test_portfolios.py index 6c1da209..9972a682 100644 --- a/tests/domain/test_portfolios.py +++ b/tests/domain/test_portfolios.py @@ -8,12 +8,7 @@ from atst.domain.applications import Applications from atst.domain.environments import Environments from atst.models.portfolio_role import Status as PortfolioRoleStatus -from tests.factories import ( - RequestFactory, - UserFactory, - PortfolioRoleFactory, - PortfolioFactory, -) +from tests.factories import UserFactory, PortfolioRoleFactory, PortfolioFactory @pytest.fixture(scope="function") @@ -22,39 +17,21 @@ def portfolio_owner(): @pytest.fixture(scope="function") -def request_(portfolio_owner): - return RequestFactory.create(creator=portfolio_owner) - - -@pytest.fixture(scope="function") -def portfolio(request_): - portfolio = Portfolios.create_from_request(request_) +def portfolio(portfolio_owner): + portfolio = PortfolioFactory.create(owner=portfolio_owner) return portfolio -def test_can_create_portfolio(request_): - portfolio = Portfolios.create_from_request(request_, name="frugal-whale") +def test_can_create_portfolio(): + portfolio = PortfolioFactory.create(name="frugal-whale") assert portfolio.name == "frugal-whale" -def test_request_is_associated_with_portfolio(portfolio, request_): - assert portfolio.request == request_ - - -def test_default_portfolio_name_is_request_name(portfolio, request_): - assert portfolio.name == str(request_.displayname) - - def test_get_nonexistent_portfolio_raises(): with pytest.raises(NotFoundError): Portfolios.get(UserFactory.build(), uuid4()) -def test_can_get_portfolio_by_request(portfolio): - found = Portfolios.get_by_request(portfolio.request) - assert portfolio == found - - def test_creating_portfolio_adds_owner(portfolio, portfolio_owner): assert portfolio.roles[0].user == portfolio_owner @@ -162,10 +139,6 @@ def test_need_permission_to_update_portfolio_role_role(portfolio, portfolio_owne def test_owner_can_view_portfolio_members(portfolio, portfolio_owner): - portfolio_owner = UserFactory.create() - portfolio = Portfolios.create_from_request( - RequestFactory.create(creator=portfolio_owner) - ) portfolio = Portfolios.get_with_members(portfolio_owner, portfolio.id) assert portfolio @@ -258,7 +231,7 @@ def test_for_user_returns_active_portfolios_for_user(portfolio, portfolio_owner) PortfolioRoleFactory.create( user=bob, portfolio=portfolio, status=PortfolioRoleStatus.ACTIVE ) - Portfolios.create_from_request(RequestFactory.create()) + PortfolioFactory.create() bobs_portfolios = Portfolios.for_user(bob) @@ -268,7 +241,7 @@ def test_for_user_returns_active_portfolios_for_user(portfolio, portfolio_owner) def test_for_user_does_not_return_inactive_portfolios(portfolio, portfolio_owner): bob = UserFactory.from_atat_role("default") Portfolios.add_member(portfolio, bob, "developer") - Portfolios.create_from_request(RequestFactory.create()) + PortfolioFactory.create() bobs_portfolios = Portfolios.for_user(bob) assert len(bobs_portfolios) == 0 @@ -276,17 +249,13 @@ def test_for_user_does_not_return_inactive_portfolios(portfolio, portfolio_owner def test_for_user_returns_all_portfolios_for_ccpo(portfolio, portfolio_owner): sam = UserFactory.from_atat_role("ccpo") - Portfolios.create_from_request(RequestFactory.create()) + PortfolioFactory.create() sams_portfolios = Portfolios.for_user(sam) assert len(sams_portfolios) == 2 -def test_get_for_update_information(): - portfolio_owner = UserFactory.create() - portfolio = Portfolios.create_from_request( - RequestFactory.create(creator=portfolio_owner) - ) +def test_get_for_update_information(portfolio, portfolio_owner): owner_ws = Portfolios.get_for_update_information(portfolio_owner, portfolio.id) assert portfolio == owner_ws @@ -307,8 +276,8 @@ def test_get_for_update_information(): def test_can_create_portfolios_with_matching_names(): portfolio_name = "Great Portfolio" - Portfolios.create_from_request(RequestFactory.create(), name=portfolio_name) - Portfolios.create_from_request(RequestFactory.create(), name=portfolio_name) + PortfolioFactory.create(name=portfolio_name) + PortfolioFactory.create(name=portfolio_name) def test_able_to_revoke_portfolio_access_for_active_member(): diff --git a/tests/domain/test_reports.py b/tests/domain/test_reports.py index 2307abcb..d0e3a24e 100644 --- a/tests/domain/test_reports.py +++ b/tests/domain/test_reports.py @@ -1,27 +1,17 @@ from atst.domain.reports import Reports -from tests.factories import RequestFactory, LegacyTaskOrderFactory, PortfolioFactory - -CLIN_NUMS = ["0001", "0003", "1001", "1003", "2001", "2003"] +from tests.factories import PortfolioFactory def test_portfolio_totals(): - legacy_task_order = LegacyTaskOrderFactory.create() - - for num in CLIN_NUMS: - setattr(legacy_task_order, "clin_{}".format(num), 200) - - request = RequestFactory.create(legacy_task_order=legacy_task_order) - portfolio = PortfolioFactory.create(request=request) + portfolio = PortfolioFactory.create() report = Reports.portfolio_totals(portfolio) - total = 200 * len(CLIN_NUMS) - assert report == {"budget": total, "spent": 0} + assert report == {"budget": 0, "spent": 0} # this is sketched in until we do real reporting def test_monthly_totals(): - request = RequestFactory.create() - portfolio = PortfolioFactory.create(request=request) + portfolio = PortfolioFactory.create() monthly = Reports.monthly_totals(portfolio) assert not monthly["environments"] @@ -31,8 +21,7 @@ def test_monthly_totals(): # this is sketched in until we do real reporting def test_cumulative_budget(): - request = RequestFactory.create() - portfolio = PortfolioFactory.create(request=request) + portfolio = PortfolioFactory.create() months = Reports.cumulative_budget(portfolio) assert len(months["months"]) >= 12 diff --git a/tests/factories.py b/tests/factories.py index fd081e34..c4d50b02 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -9,10 +9,6 @@ from faker import Faker as _Faker from atst.forms import data from atst.models.attachment import Attachment from atst.models.environment import Environment -from atst.models.request import Request -from atst.models.request_revision import RequestRevision -from atst.models.request_review import RequestReview -from atst.models.request_status_event import RequestStatusEvent, RequestStatus from atst.models.pe_number import PENumber from atst.models.application import Application from atst.models.legacy_task_order import LegacyTaskOrder, Source, FundingType @@ -105,142 +101,6 @@ class UserFactory(Base): return cls.create(atat_role=role, **kwargs) -class RequestStatusEventFactory(Base): - class Meta: - model = RequestStatusEvent - - id = factory.Sequence(lambda x: uuid4()) - sequence = 1 - - -class RequestRevisionFactory(Base): - class Meta: - model = RequestRevision - - id = factory.Sequence(lambda x: uuid4()) - - -class RequestReviewFactory(Base): - class Meta: - model = RequestReview - - comment = factory.Faker("sentence") - fname_mao = factory.Faker("first_name") - lname_mao = factory.Faker("last_name") - email_mao = factory.Faker("email") - phone_mao = factory.LazyFunction( - lambda: "".join(random.choices(string.digits, k=10)) - ) - fname_ccpo = factory.Faker("first_name") - lname_ccpo = factory.Faker("last_name") - - -class RequestFactory(Base): - class Meta: - model = Request - - id = factory.Sequence(lambda x: uuid4()) - creator = factory.SubFactory(UserFactory) - revisions = factory.LazyAttribute( - lambda r: [RequestFactory.create_initial_revision(r)] - ) - status_events = factory.RelatedFactory( - RequestStatusEventFactory, - "request", - new_status=RequestStatus.STARTED, - revision=factory.LazyAttribute(lambda se: se.factory_parent.revisions[-1]), - ) - - class Params: - initial_revision = None - - @classmethod - def _adjust_kwargs(cls, **kwargs): - if kwargs.pop("with_task_order", False) and "legacy_task_order" not in kwargs: - kwargs["legacy_task_order"] = LegacyTaskOrderFactory.build() - return kwargs - - @classmethod - def create_initial_status_event(cls, request): - return RequestStatusEventFactory( - request=request, - new_status=RequestStatus.STARTED, - revision=request.revisions, - ) - - @classmethod - def create_initial_revision(cls, request, dollar_value=1_000_000): - user = request.creator - default_data = dict( - name=factory.Faker("domain_word"), - am_poc=False, - dodid_poc=user.dod_id, - email_poc=user.email, - fname_poc=user.first_name, - lname_poc=user.last_name, - jedi_usage="adf", - start_date=datetime.date(2050, 1, 1), - cloud_native="yes", - dollar_value=dollar_value, - dod_component=random_service_branch(), - data_transfers="Less than 100GB", - expected_completion_date="Less than 1 month", - jedi_migration="yes", - num_software_systems=1, - number_user_sessions=2, - average_daily_traffic=1, - engineering_assessment="yes", - technical_support_team="yes", - estimated_monthly_spend=100, - average_daily_traffic_gb=4, - rationalization_software_systems="yes", - organization_providing_assistance="In-house staff", - citizenship="United States", - designation="military", - phone_number="1234567890", - phone_ext="123", - email_request=user.email, - fname_request=user.first_name, - lname_request=user.last_name, - service_branch=random_service_branch(), - date_latest_training=datetime.date(2018, 8, 6), - ) - - data = ( - request.initial_revision - if request.initial_revision is not None - else default_data - ) - - return RequestRevisionFactory.build(**data) - - @classmethod - def create_with_status(cls, status=RequestStatus.STARTED, **kwargs): - request = RequestFactory(**kwargs) - RequestStatusEventFactory.create( - request=request, revision=request.latest_revision, new_status=status - ) - return request - - @classmethod - def mock_financial_data(cls): - fake = _Faker() - return { - "pe_id": "0101110F", - "fname_co": fake.first_name(), - "lname_co": fake.last_name(), - "email_co": fake.email(), - "office_co": fake.phone_number(), - "fname_cor": fake.first_name(), - "lname_cor": fake.last_name(), - "email_cor": fake.email(), - "office_cor": fake.phone_number(), - "uii_ids": "123abc", - "treasury_code": "00123456", - "ba_code": "02A", - } - - class PENumberFactory(Base): class Meta: model = PENumber @@ -269,9 +129,7 @@ class PortfolioFactory(Base): class Meta: model = Portfolio - request = factory.SubFactory(RequestFactory, with_task_order=True) - # name it the same as the request ID by default - name = factory.LazyAttribute(lambda w: w.request.id) + name = factory.Faker("name") @classmethod def _create(cls, model_class, *args, **kwargs): @@ -286,7 +144,6 @@ class PortfolioFactory(Base): for p in with_applications ] - portfolio.request.creator = owner PortfolioRoleFactory.create( portfolio=portfolio, role=Roles.get("owner"), diff --git a/tests/mocks.py b/tests/mocks.py index f5e9c2d3..8536eec8 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -1,4 +1,4 @@ -from tests.factories import RequestFactory, UserFactory +from tests.factories import UserFactory DOD_SDN_INFO = {"first_name": "ART", "last_name": "GARFUNKEL", "dod_id": "5892460358"} diff --git a/tests/models/test_environments.py b/tests/models/test_environments.py index cf48f2b1..1e415efa 100644 --- a/tests/models/test_environments.py +++ b/tests/models/test_environments.py @@ -1,14 +1,13 @@ from atst.domain.environments import Environments -from atst.domain.portfolios import Portfolios from atst.domain.applications import Applications -from tests.factories import RequestFactory, UserFactory +from tests.factories import PortfolioFactory, UserFactory def test_add_user_to_environment(): owner = UserFactory.create() developer = UserFactory.from_atat_role("developer") - portfolio = Portfolios.create_from_request(RequestFactory.create(creator=owner)) + portfolio = PortfolioFactory.create(owner=owner) application = Applications.create( owner, portfolio, diff --git a/tests/models/test_portfolio_role.py b/tests/models/test_portfolio_role.py index 33d8d119..06db96e3 100644 --- a/tests/models/test_portfolio_role.py +++ b/tests/models/test_portfolio_role.py @@ -9,7 +9,6 @@ from atst.models.invitation import Status as InvitationStatus from atst.models.audit_event import AuditEvent from atst.models.portfolio_role import Status as PortfolioRoleStatus from tests.factories import ( - RequestFactory, UserFactory, InvitationFactory, PortfolioRoleFactory, @@ -25,7 +24,7 @@ def test_has_no_ws_role_history(session): owner = UserFactory.create() user = UserFactory.create() - portfolio = Portfolios.create_from_request(RequestFactory.create(creator=owner)) + portfolio = PortfolioFactory.create(owner=owner) portfolio_role = PortfolioRoles.add(user, portfolio.id, "developer") create_event = ( session.query(AuditEvent) @@ -42,7 +41,7 @@ def test_has_ws_role_history(session): owner = UserFactory.create() user = UserFactory.create() - portfolio = Portfolios.create_from_request(RequestFactory.create(creator=owner)) + portfolio = PortfolioFactory.create(owner=owner) role = session.query(Role).filter(Role.name == "developer").one() # in order to get the history, we don't want the PortfolioRoleFactory # to commit after create() @@ -67,7 +66,7 @@ def test_has_ws_status_history(session): owner = UserFactory.create() user = UserFactory.create() - portfolio = Portfolios.create_from_request(RequestFactory.create(creator=owner)) + portfolio = PortfolioFactory.create(owner=owner) # in order to get the history, we don't want the PortfolioRoleFactory # to commit after create() PortfolioRoleFactory._meta.sqlalchemy_session_persistence = "flush" @@ -89,7 +88,7 @@ def test_has_ws_status_history(session): def test_has_no_env_role_history(session): owner = UserFactory.create() user = UserFactory.create() - portfolio = Portfolios.create_from_request(RequestFactory.create(creator=owner)) + portfolio = PortfolioFactory.create(owner=owner) application = ApplicationFactory.create(portfolio=portfolio) environment = EnvironmentFactory.create( application=application, name="new environment!" @@ -110,7 +109,7 @@ def test_has_no_env_role_history(session): def test_has_env_role_history(session): owner = UserFactory.create() user = UserFactory.create() - portfolio = Portfolios.create_from_request(RequestFactory.create(creator=owner)) + portfolio = PortfolioFactory.create(owner=owner) portfolio_role = PortfolioRoleFactory.create(portfolio=portfolio, user=user) application = ApplicationFactory.create(portfolio=portfolio) environment = EnvironmentFactory.create( @@ -137,7 +136,7 @@ def test_event_details(): owner = UserFactory.create() user = UserFactory.create() - portfolio = Portfolios.create_from_request(RequestFactory.create(creator=owner)) + portfolio = PortfolioFactory.create(owner=owner) portfolio_role = PortfolioRoles.add(user, portfolio.id, "developer") assert portfolio_role.event_details["updated_user_name"] == user.displayname @@ -154,7 +153,7 @@ def test_has_no_environment_roles(): "portfolio_role": "developer", } - portfolio = Portfolios.create_from_request(RequestFactory.create(creator=owner)) + portfolio = PortfolioFactory.create(owner=owner) portfolio_role = Portfolios.create_member(owner, portfolio, developer_data) assert not portfolio_role.has_environment_roles @@ -170,7 +169,7 @@ def test_has_environment_roles(): "portfolio_role": "developer", } - portfolio = Portfolios.create_from_request(RequestFactory.create(creator=owner)) + portfolio = PortfolioFactory.create(owner=owner) portfolio_role = Portfolios.create_member(owner, portfolio, developer_data) application = Applications.create( owner, @@ -195,7 +194,7 @@ def test_role_displayname(): "portfolio_role": "developer", } - portfolio = Portfolios.create_from_request(RequestFactory.create(creator=owner)) + portfolio = PortfolioFactory.create(owner=owner) portfolio_role = Portfolios.create_member(owner, portfolio, developer_data) assert portfolio_role.role_displayname == "Developer" diff --git a/tests/routes/test_home.py b/tests/routes/test_home.py index b2dd8d95..3e749efb 100644 --- a/tests/routes/test_home.py +++ b/tests/routes/test_home.py @@ -1,28 +1,27 @@ import pytest -from tests.factories import UserFactory, PortfolioFactory, RequestFactory +from tests.factories import UserFactory, PortfolioFactory from atst.domain.portfolios import Portfolios from atst.models.portfolio_role import Status as PortfolioRoleStatus -def test_request_owner_with_one_portfolio_redirected_to_reports(client, user_session): - request = RequestFactory.create() - portfolio = Portfolios.create_from_request(request) +def test_portfolio_owner_with_one_portfolio_redirected_to_reports(client, user_session): + portfolio = PortfolioFactory.create() - user_session(request.creator) + user_session(portfolio.owner) response = client.get("/home", follow_redirects=False) assert "/portfolios/{}/reports".format(portfolio.id) in response.location -def test_request_owner_with_more_than_one_portfolio_redirected_to_portfolios( +def test_portfolio_owner_with_more_than_one_portfolio_redirected_to_portfolios( client, user_session ): - request_creator = UserFactory.create() - Portfolios.create_from_request(RequestFactory.create(creator=request_creator)) - Portfolios.create_from_request(RequestFactory.create(creator=request_creator)) + owner = UserFactory.create() + PortfolioFactory.create(owner=owner) + PortfolioFactory.create(owner=owner) - user_session(request_creator) + user_session(owner) response = client.get("/home", follow_redirects=False) assert "/portfolios" in response.location