diff --git a/alembic/versions/da9d1c911a52_remove_status_column_from_task_order.py b/alembic/versions/da9d1c911a52_remove_status_column_from_task_order.py new file mode 100644 index 00000000..2847546c --- /dev/null +++ b/alembic/versions/da9d1c911a52_remove_status_column_from_task_order.py @@ -0,0 +1,28 @@ +"""Remove status column from task order + +Revision ID: da9d1c911a52 +Revises: a6837632686c +Create Date: 2019-01-14 11:21:51.729134 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'da9d1c911a52' +down_revision = 'a6837632686c' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('task_orders', 'status') + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('task_orders', sa.Column('status', sa.VARCHAR(length=7), autoincrement=False, nullable=True)) + # ### end Alembic commands ### diff --git a/atst/models/task_order.py b/atst/models/task_order.py index 86e67443..340be9af 100644 --- a/atst/models/task_order.py +++ b/atst/models/task_order.py @@ -1,14 +1,7 @@ from enum import Enum -from sqlalchemy import ( - Column, - Enum as SQLAEnum, - Numeric, - String, - ForeignKey, - Date, - Integer, -) +import pendulum +from sqlalchemy import Column, Numeric, String, ForeignKey, Date, Integer from sqlalchemy.types import ARRAY from sqlalchemy.orm import relationship @@ -17,6 +10,8 @@ from atst.models import Base, types, mixins class Status(Enum): PENDING = "Pending" + ACTIVE = "Active" + EXPIRED = "Expired" class TaskOrder(Base, mixins.TimestampsMixin): @@ -41,8 +36,6 @@ class TaskOrder(Base, mixins.TimestampsMixin): so_id = Column(ForeignKey("users.id")) security_officer = relationship("User", foreign_keys="TaskOrder.so_id") - status = Column(SQLAEnum(Status, native_enum=False)) - scope = Column(String) # Cloud Project Scope defense_component = Column(String) # Department of Defense Component app_migration = Column(String) # App Migration @@ -79,10 +72,21 @@ class TaskOrder(Base, mixins.TimestampsMixin): number = Column(String, unique=True) # Task Order Number loa = Column(ARRAY(String)) # Line of Accounting (LOA) - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - if "status" not in kwargs: - self.status = Status.PENDING + @property + def is_submitted(self): + return self.number is not None + + @property + def status(self): + if self.is_submitted: + now = pendulum.now().date() + if self.start_date > now: + return Status.PENDING + elif self.end_date < now: + return Status.EXPIRED + return Status.ACTIVE + else: + return Status.PENDING @property def budget(self): diff --git a/script/format b/script/format index c8997ed3..1ef619a1 100755 --- a/script/format +++ b/script/format @@ -1,6 +1,6 @@ #!/bin/bash -FILES_TO_FORMAT="atst/ tests/ app.py" +FILES_TO_FORMAT="atst/ tests/ app.py script/" if [ "$1" == "check" ]; then pipenv run black --check ${FILES_TO_FORMAT} diff --git a/script/ingest_pe_numbers.py b/script/ingest_pe_numbers.py index b709be83..c6abe387 100644 --- a/script/ingest_pe_numbers.py +++ b/script/ingest_pe_numbers.py @@ -4,7 +4,8 @@ import csv # Add root project dir to the python path import os import sys -parent_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) + +parent_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) sys.path.append(parent_dir) from atst.app import make_app, make_config @@ -16,9 +17,10 @@ def get_pe_numbers(url): t = response.read().decode("utf-8") return list(csv.reader(t.split("\r\n"))) + if __name__ == "__main__": config = make_config() - url = config['PE_NUMBER_CSV_URL'] + url = config["PE_NUMBER_CSV_URL"] print("Fetching PE numbers from {}".format(url)) pe_numbers = get_pe_numbers(url) diff --git a/script/remove_sample_data.py b/script/remove_sample_data.py index becde60a..e736c1da 100644 --- a/script/remove_sample_data.py +++ b/script/remove_sample_data.py @@ -41,19 +41,21 @@ dod_ids = [ "4567890123", "5678901234", "6789012345", - "2342342342", # Andy - "3453453453", # Sally - "4564564564", # Betty + "2342342342", # Andy + "3453453453", # Sally + "4564564564", # Betty "6786786786", ] def create_demo_portfolio(name, data): try: - portfolio_owner = Users.get_by_dod_id("678678678") # Other - auditor = Users.get_by_dod_id("3453453453") # Sally + portfolio_owner = Users.get_by_dod_id("678678678") # Other + auditor = Users.get_by_dod_id("3453453453") # Sally except NotFoundError: - print("Could not find demo users; will not create demo portfolio {}".format(name)) + print( + "Could not find demo users; will not create demo portfolio {}".format(name) + ) return request = RequestFactory.build(creator=portfolio_owner) @@ -64,10 +66,12 @@ def create_demo_portfolio(name, data): approved_request = Requests.set_status(request, RequestStatus.APPROVED) portfolio = Requests.approve_and_create_portfolio(request) - portfolios.update(portfolio, { "name": name }) + portfolios.update(portfolio, {"name": name}) for mock_application in data["applications"]: - application = application(portfolio=portfolio, name=mock_application.name, description='') + application = application( + portfolio=portfolio, name=mock_application.name, description="" + ) env_names = [env.name for env in mock_application.environments] envs = Environments.create_many(application, env_names) db.session.add(application) @@ -153,5 +157,9 @@ if __name__ == "__main__": app = make_app(config) with app.app_context(): remove_sample_data() - create_demo_portfolio('Aardvark', MockReportingProvider.REPORT_FIXTURE_MAP["Aardvark"]) - create_demo_portfolio('Beluga', MockReportingProvider.REPORT_FIXTURE_MAP["Beluga"]) + create_demo_portfolio( + "Aardvark", MockReportingProvider.REPORT_FIXTURE_MAP["Aardvark"] + ) + create_demo_portfolio( + "Beluga", MockReportingProvider.REPORT_FIXTURE_MAP["Beluga"] + ) diff --git a/script/seed_sample.py b/script/seed_sample.py index 3876f07a..1395d7b0 100644 --- a/script/seed_sample.py +++ b/script/seed_sample.py @@ -14,10 +14,17 @@ from atst.domain.applications import Applications from atst.domain.portfolio_roles import PortfolioRoles from atst.models.invitation import Status as InvitationStatus from atst.domain.exceptions import AlreadyExistsError -from tests.factories import RequestFactory, LegacyTaskOrderFactory, InvitationFactory +from tests.factories import ( + InvitationFactory, + RequestFactory, + TaskOrderFactory, + random_future_date, + random_past_date, + random_task_order_number, +) from atst.routes.dev import _DEV_USERS as DEV_USERS -portfolio_USERS = [ +PORTFOLIO_USERS = [ { "first_name": "Danny", "last_name": "Knight", @@ -48,7 +55,7 @@ PORTFOLIO_INVITED_USERS = [ "email": "frederick@mil.gov", "portfolio_role": "developer", "dod_id": "0000000004", - "status": InvitationStatus.REJECTED_WRONG_USER + "status": InvitationStatus.REJECTED_WRONG_USER, }, { "first_name": "Gina", @@ -56,7 +63,7 @@ PORTFOLIO_INVITED_USERS = [ "email": "gina@mil.gov", "portfolio_role": "developer", "dod_id": "0000000005", - "status": InvitationStatus.REJECTED_EXPIRED + "status": InvitationStatus.REJECTED_EXPIRED, }, { "first_name": "Hector", @@ -64,7 +71,7 @@ PORTFOLIO_INVITED_USERS = [ "email": "hector@mil.gov", "portfolio_role": "developer", "dod_id": "0000000006", - "status": InvitationStatus.REVOKED + "status": InvitationStatus.REVOKED, }, { "first_name": "Isabella", @@ -72,7 +79,7 @@ PORTFOLIO_INVITED_USERS = [ "email": "isabella@mil.gov", "portfolio_role": "developer", "dod_id": "0000000007", - "status": InvitationStatus.PENDING + "status": InvitationStatus.PENDING, }, ] @@ -88,38 +95,45 @@ def seed_db(): users.append(user) for user in users: - if Requests.get_many(creator=user): - continue - - requests = [] - for dollar_value in [1, 200, 3000, 40000, 500000, 1000000]: - request = RequestFactory.build(creator=user) - request.latest_revision.dollar_value = dollar_value - db.session.add(request) - db.session.commit() - - Requests.submit(request) - requests.append(request) - - request = requests[0] - request.legacy_task_order = LegacyTaskOrderFactory.build() - request = Requests.update( - request.id, {"financial_verification": RequestFactory.mock_financial_data()} - ) - portfolio = Portfolios.create( user, name="{}'s portfolio".format(user.first_name) ) - for portfolio_role in portfolio_USERS: + for portfolio_role in PORTFOLIO_USERS: ws_role = Portfolios.create_member(user, portfolio, portfolio_role) db.session.refresh(ws_role) PortfolioRoles.enable(ws_role) for portfolio_role in PORTFOLIO_INVITED_USERS: ws_role = Portfolios.create_member(user, portfolio, portfolio_role) - invitation = InvitationFactory.build(portfolio_role=ws_role, status=portfolio_role["status"]) + invitation = InvitationFactory.build( + portfolio_role=ws_role, status=portfolio_role["status"] + ) db.session.add(invitation) + [expired_start, expired_end] = sorted( + [ + random_past_date(year_max=2, year_min=1), + random_past_date(year_max=1, year_min=1), + ] + ) + active_start = expired_end + active_end = random_future_date(year_min=1, year_max=1) + + date_ranges = [(expired_start, expired_end), (active_start, active_end)] + for (start_date, end_date) in date_ranges: + task_order = TaskOrderFactory.build( + start_date=start_date, + end_date=end_date, + number=random_task_order_number(), + portfolio=portfolio, + ) + db.session.add(task_order) + + pending_task_order = TaskOrderFactory.build( + start_date=None, end_date=None, number=None, portfolio=portfolio + ) + db.session.add(pending_task_order) + db.session.commit() Applications.create( diff --git a/styles/sections/_task_order.scss b/styles/sections/_task_order.scss index af927b3b..c8d12f4f 100644 --- a/styles/sections/_task_order.scss +++ b/styles/sections/_task_order.scss @@ -56,6 +56,18 @@ } } + .label--pending { + background-color: $color-gold; + } + + .label--active { + background-color: $color-green; + } + + .label--expired { + background-color: $color-red; + } + .task-order-heading { align-items: center; justify-content: space-between; diff --git a/templates/portfolios/task_orders/show.html b/templates/portfolios/task_orders/show.html index 17a400c4..6ee1ab3c 100644 --- a/templates/portfolios/task_orders/show.html +++ b/templates/portfolios/task_orders/show.html @@ -63,7 +63,7 @@