Merge pull request #677 from dod-ccpo/move-component-to-portfolio
Move defense_component to portfolios model
This commit is contained in:
commit
3849a69e99
@ -0,0 +1,52 @@
|
|||||||
|
"""Move defense component to Portfolio level
|
||||||
|
|
||||||
|
Revision ID: ec1ba2363191
|
||||||
|
Revises: fb22e47972a3
|
||||||
|
Create Date: 2019-02-22 14:43:49.408446
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy.sql import text
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'ec1ba2363191'
|
||||||
|
down_revision = 'fb22e47972a3'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column('portfolios', sa.Column('defense_component', sa.String(), nullable=True))
|
||||||
|
conn = op.get_bind()
|
||||||
|
conn.execute(
|
||||||
|
text(
|
||||||
|
"""
|
||||||
|
UPDATE portfolios
|
||||||
|
SET defense_component = task_orders.defense_component
|
||||||
|
FROM task_orders
|
||||||
|
WHERE task_orders.portfolio_id = portfolios.id;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
op.drop_column('task_orders', 'defense_component')
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column('task_orders', sa.Column('defense_component', sa.VARCHAR(), autoincrement=False, nullable=True))
|
||||||
|
conn = op.get_bind()
|
||||||
|
conn.execute(
|
||||||
|
text(
|
||||||
|
"""
|
||||||
|
UPDATE task_orders
|
||||||
|
SET defense_component = portfolios.defense_component
|
||||||
|
FROM portfolios;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
op.drop_column('portfolios', 'defense_component')
|
||||||
|
# ### end Alembic commands ###
|
@ -16,8 +16,10 @@ class PortfolioError(Exception):
|
|||||||
|
|
||||||
class Portfolios(object):
|
class Portfolios(object):
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, user, name):
|
def create(cls, user, name, defense_component):
|
||||||
portfolio = PortfoliosQuery.create(name=name)
|
portfolio = PortfoliosQuery.create(
|
||||||
|
name=name, defense_component=defense_component
|
||||||
|
)
|
||||||
Portfolios._create_portfolio_role(
|
Portfolios._create_portfolio_role(
|
||||||
user, portfolio, "owner", status=PortfolioRoleStatus.ACTIVE
|
user, portfolio, "owner", status=PortfolioRoleStatus.ACTIVE
|
||||||
)
|
)
|
||||||
|
@ -13,6 +13,8 @@ class Portfolio(Base, mixins.TimestampsMixin, mixins.AuditableMixin):
|
|||||||
|
|
||||||
id = types.Id()
|
id = types.Id()
|
||||||
name = Column(String)
|
name = Column(String)
|
||||||
|
defense_component = Column(String) # Department of Defense Component
|
||||||
|
|
||||||
applications = relationship("Application", back_populates="portfolio")
|
applications = relationship("Application", back_populates="portfolio")
|
||||||
roles = relationship("PortfolioRole")
|
roles = relationship("PortfolioRole")
|
||||||
|
|
||||||
|
@ -53,7 +53,6 @@ class TaskOrder(Base, mixins.TimestampsMixin):
|
|||||||
dd_254 = relationship("DD254")
|
dd_254 = relationship("DD254")
|
||||||
|
|
||||||
scope = Column(String) # Cloud Project Scope
|
scope = Column(String) # Cloud Project Scope
|
||||||
defense_component = Column(String) # Department of Defense Component
|
|
||||||
app_migration = Column(String) # App Migration
|
app_migration = Column(String) # App Migration
|
||||||
native_apps = Column(String) # Native Apps
|
native_apps = Column(String) # Native Apps
|
||||||
complexity = Column(ARRAY(String)) # Application Complexity
|
complexity = Column(ARRAY(String)) # Application Complexity
|
||||||
@ -172,6 +171,10 @@ class TaskOrder(Base, mixins.TimestampsMixin):
|
|||||||
def portfolio_name(self):
|
def portfolio_name(self):
|
||||||
return self.portfolio.name
|
return self.portfolio.name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def defense_component(self):
|
||||||
|
return self.portfolio.defense_component
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_pending(self):
|
def is_pending(self):
|
||||||
return self.status == Status.PENDING
|
return self.status == Status.PENDING
|
||||||
|
@ -149,6 +149,8 @@ class UpdateTaskOrderWorkflow(ShowTaskOrderWorkflow):
|
|||||||
to_data = self.form.data.copy()
|
to_data = self.form.data.copy()
|
||||||
if "portfolio_name" in to_data:
|
if "portfolio_name" in to_data:
|
||||||
to_data.pop("portfolio_name")
|
to_data.pop("portfolio_name")
|
||||||
|
if "defense_component" in to_data:
|
||||||
|
to_data.pop("defense_component")
|
||||||
|
|
||||||
# don't save other text in DB unless "other" is checked
|
# don't save other text in DB unless "other" is checked
|
||||||
if "complexity" in to_data and "other" not in to_data["complexity"]:
|
if "complexity" in to_data and "other" not in to_data["complexity"]:
|
||||||
@ -184,7 +186,11 @@ class UpdateTaskOrderWorkflow(ShowTaskOrderWorkflow):
|
|||||||
if self.portfolio_id:
|
if self.portfolio_id:
|
||||||
pf = Portfolios.get(self.user, self.portfolio_id)
|
pf = Portfolios.get(self.user, self.portfolio_id)
|
||||||
else:
|
else:
|
||||||
pf = Portfolios.create(self.user, self.form.portfolio_name.data)
|
pf = Portfolios.create(
|
||||||
|
self.user,
|
||||||
|
self.form.portfolio_name.data,
|
||||||
|
self.form.defense_component.data,
|
||||||
|
)
|
||||||
self._task_order = TaskOrders.create(portfolio=pf, creator=self.user)
|
self._task_order = TaskOrders.create(portfolio=pf, creator=self.user)
|
||||||
TaskOrders.update(self.user, self.task_order, **self.task_order_form_data)
|
TaskOrders.update(self.user, self.task_order, **self.task_order_form_data)
|
||||||
|
|
||||||
|
@ -446,6 +446,8 @@
|
|||||||
|
|
||||||
.form-col {
|
.form-col {
|
||||||
.usa-input--validation--portfolioName {
|
.usa-input--validation--portfolioName {
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
input {
|
input {
|
||||||
max-width: 30em;
|
max-width: 30em;
|
||||||
}
|
}
|
||||||
@ -455,4 +457,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.defense-row {
|
||||||
|
.admin-title {
|
||||||
|
padding: 0 0 0.4rem 0;
|
||||||
|
margin-top: 0;
|
||||||
|
font-size: 1.7rem;
|
||||||
|
font-weight: 700;
|
||||||
|
max-width: 45em;
|
||||||
|
position: relative;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-content {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,12 @@
|
|||||||
<button type="submit" class="usa-button usa-button-big usa-button-primary" tabindex="0">Save</button>
|
<button type="submit" class="usa-button usa-button-big usa-button-primary" tabindex="0">Save</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class='defense-row'>
|
||||||
|
<div>
|
||||||
|
<div class='admin-title'>{{ "forms.task_order.defense_component_label" | translate }}</div>
|
||||||
|
<div class='admin-content'>{{ portfolio.defense_component }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% include "fragments/audit_events_log.html" %}
|
{% include "fragments/audit_events_log.html" %}
|
||||||
|
@ -29,12 +29,12 @@ def test_section_completion_status():
|
|||||||
section = dict_keys[0]
|
section = dict_keys[0]
|
||||||
attrs = TaskOrders.SECTIONS[section].copy()
|
attrs = TaskOrders.SECTIONS[section].copy()
|
||||||
attrs.remove("portfolio_name")
|
attrs.remove("portfolio_name")
|
||||||
|
attrs.remove("defense_component")
|
||||||
task_order = TaskOrderFactory.create(**{k: None for k in attrs})
|
task_order = TaskOrderFactory.create(**{k: None for k in attrs})
|
||||||
leftover = attrs.pop()
|
leftover = attrs.pop()
|
||||||
|
|
||||||
for attr in attrs:
|
for attr in attrs:
|
||||||
setattr(task_order, attr, "str12345")
|
setattr(task_order, attr, "str12345")
|
||||||
|
|
||||||
assert TaskOrders.section_completion_status(task_order, section) == "draft"
|
assert TaskOrders.section_completion_status(task_order, section) == "draft"
|
||||||
|
|
||||||
setattr(task_order, leftover, "str12345")
|
setattr(task_order, leftover, "str12345")
|
||||||
|
@ -104,6 +104,7 @@ class PortfolioFactory(Base):
|
|||||||
model = Portfolio
|
model = Portfolio
|
||||||
|
|
||||||
name = factory.Faker("name")
|
name = factory.Faker("name")
|
||||||
|
defense_component = factory.LazyFunction(random_service_branch)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _create(cls, model_class, *args, **kwargs):
|
def _create(cls, model_class, *args, **kwargs):
|
||||||
@ -227,7 +228,6 @@ class TaskOrderFactory(Base):
|
|||||||
clin_02 = factory.LazyFunction(lambda *args: random.randrange(100, 100_000))
|
clin_02 = factory.LazyFunction(lambda *args: random.randrange(100, 100_000))
|
||||||
clin_04 = factory.LazyFunction(lambda *args: random.randrange(100, 100_000))
|
clin_04 = factory.LazyFunction(lambda *args: random.randrange(100, 100_000))
|
||||||
|
|
||||||
defense_component = factory.LazyFunction(random_service_branch)
|
|
||||||
app_migration = random_choice(data.APP_MIGRATION)
|
app_migration = random_choice(data.APP_MIGRATION)
|
||||||
native_apps = random.choice(["yes", "no", "not_sure"])
|
native_apps = random.choice(["yes", "no", "not_sure"])
|
||||||
complexity = [random_choice(data.APPLICATION_COMPLEXITY)]
|
complexity = [random_choice(data.APPLICATION_COMPLEXITY)]
|
||||||
|
@ -51,7 +51,9 @@ def test_create_new_task_order(client, user_session, pdf_upload):
|
|||||||
task_order_data = TaskOrderFactory.dictionary()
|
task_order_data = TaskOrderFactory.dictionary()
|
||||||
app_info_data = slice_data_for_section(task_order_data, "app_info")
|
app_info_data = slice_data_for_section(task_order_data, "app_info")
|
||||||
portfolio_name = "Mos Eisley"
|
portfolio_name = "Mos Eisley"
|
||||||
|
defense_component = "Defense Health Agency"
|
||||||
app_info_data["portfolio_name"] = portfolio_name
|
app_info_data["portfolio_name"] = portfolio_name
|
||||||
|
app_info_data["defense_component"] = defense_component
|
||||||
|
|
||||||
response = client.post(
|
response = client.post(
|
||||||
url_for("task_orders.update", screen=1),
|
url_for("task_orders.update", screen=1),
|
||||||
@ -64,6 +66,8 @@ def test_create_new_task_order(client, user_session, pdf_upload):
|
|||||||
created_task_order = TaskOrders.get(creator, created_task_order_id)
|
created_task_order = TaskOrders.get(creator, created_task_order_id)
|
||||||
assert created_task_order.portfolio is not None
|
assert created_task_order.portfolio is not None
|
||||||
assert created_task_order.portfolio.name == portfolio_name
|
assert created_task_order.portfolio.name == portfolio_name
|
||||||
|
assert created_task_order.portfolio is not None
|
||||||
|
assert created_task_order.portfolio.defense_component == defense_component
|
||||||
|
|
||||||
funding_data = slice_data_for_section(task_order_data, "funding")
|
funding_data = slice_data_for_section(task_order_data, "funding")
|
||||||
funding_data = serialize_dates(funding_data)
|
funding_data = serialize_dates(funding_data)
|
||||||
@ -89,6 +93,8 @@ def test_create_new_task_order_for_portfolio(client, user_session):
|
|||||||
app_info_data = slice_data_for_section(task_order_data, "app_info")
|
app_info_data = slice_data_for_section(task_order_data, "app_info")
|
||||||
portfolio_name = "This is ignored for now"
|
portfolio_name = "This is ignored for now"
|
||||||
app_info_data["portfolio_name"] = portfolio_name
|
app_info_data["portfolio_name"] = portfolio_name
|
||||||
|
defense_component = "Defense Health Agency" # this is also ignored
|
||||||
|
app_info_data["defense_component"] = defense_component
|
||||||
|
|
||||||
response = client.post(
|
response = client.post(
|
||||||
url_for("task_orders.update", screen=1, portfolio_id=portfolio.id),
|
url_for("task_orders.update", screen=1, portfolio_id=portfolio.id),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user