commit
70617938d8
@ -163,7 +163,7 @@ class MockReportingProvider(ReportingInterface):
|
|||||||
"FM_Prod": {FIXTURE_MONTHS[0]: 5686},
|
"FM_Prod": {FIXTURE_MONTHS[0]: 5686},
|
||||||
}
|
}
|
||||||
|
|
||||||
CUMULATIVE_BUDGET_AARDVARK = {
|
CUMULATIVE_BUDGET_A_WING = {
|
||||||
FIXTURE_MONTHS[7]: {"spend": 9857, "cumulative": 9857},
|
FIXTURE_MONTHS[7]: {"spend": 9857, "cumulative": 9857},
|
||||||
FIXTURE_MONTHS[6]: {"spend": 7881, "cumulative": 17738},
|
FIXTURE_MONTHS[6]: {"spend": 7881, "cumulative": 17738},
|
||||||
FIXTURE_MONTHS[5]: {"spend": 14010, "cumulative": 31748},
|
FIXTURE_MONTHS[5]: {"spend": 14010, "cumulative": 31748},
|
||||||
@ -174,14 +174,14 @@ class MockReportingProvider(ReportingInterface):
|
|||||||
FIXTURE_MONTHS[0]: {"spend": 36028, "cumulative": 241_831},
|
FIXTURE_MONTHS[0]: {"spend": 36028, "cumulative": 241_831},
|
||||||
}
|
}
|
||||||
|
|
||||||
CUMULATIVE_BUDGET_BELUGA = {
|
CUMULATIVE_BUDGET_B_WING = {
|
||||||
FIXTURE_MONTHS[1]: {"spend": 4838, "cumulative": 4838},
|
FIXTURE_MONTHS[1]: {"spend": 4838, "cumulative": 4838},
|
||||||
FIXTURE_MONTHS[0]: {"spend": 14500, "cumulative": 19338},
|
FIXTURE_MONTHS[0]: {"spend": 14500, "cumulative": 19338},
|
||||||
}
|
}
|
||||||
|
|
||||||
REPORT_FIXTURE_MAP = {
|
REPORT_FIXTURE_MAP = {
|
||||||
"Aardvark": {
|
"A-Wing": {
|
||||||
"cumulative": CUMULATIVE_BUDGET_AARDVARK,
|
"cumulative": CUMULATIVE_BUDGET_A_WING,
|
||||||
"applications": [
|
"applications": [
|
||||||
MockApplication("LC04", ["Integ", "PreProd", "Prod"]),
|
MockApplication("LC04", ["Integ", "PreProd", "Prod"]),
|
||||||
MockApplication("SF18", ["Integ", "PreProd", "Prod"]),
|
MockApplication("SF18", ["Integ", "PreProd", "Prod"]),
|
||||||
@ -201,8 +201,8 @@ class MockReportingProvider(ReportingInterface):
|
|||||||
],
|
],
|
||||||
"budget": 500_000,
|
"budget": 500_000,
|
||||||
},
|
},
|
||||||
"Beluga": {
|
"B-Wing": {
|
||||||
"cumulative": CUMULATIVE_BUDGET_BELUGA,
|
"cumulative": CUMULATIVE_BUDGET_B_WING,
|
||||||
"applications": [
|
"applications": [
|
||||||
MockApplication("NP02", ["Integ", "PreProd", "Prod"]),
|
MockApplication("NP02", ["Integ", "PreProd", "Prod"]),
|
||||||
MockApplication("FM", ["Integ", "Prod"]),
|
MockApplication("FM", ["Integ", "Prod"]),
|
||||||
|
@ -19,6 +19,11 @@ from werkzeug.datastructures import FileStorage
|
|||||||
|
|
||||||
from atst.models import Attachment, Base, types, mixins
|
from atst.models import Attachment, Base, types, mixins
|
||||||
|
|
||||||
|
# Imports used for mocking TO balance
|
||||||
|
from atst.domain.csp.reports import MockReportingProvider
|
||||||
|
from flask import current_app as app
|
||||||
|
import random
|
||||||
|
|
||||||
|
|
||||||
class Status(Enum):
|
class Status(Enum):
|
||||||
STARTED = "Started"
|
STARTED = "Started"
|
||||||
@ -135,6 +140,10 @@ class TaskOrder(Base, mixins.TimestampsMixin):
|
|||||||
def is_active(self):
|
def is_active(self):
|
||||||
return self.status == Status.ACTIVE
|
return self.status == Status.ACTIVE
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_expired(self):
|
||||||
|
return self.status == Status.EXPIRED
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def status(self):
|
def status(self):
|
||||||
if self.is_submitted:
|
if self.is_submitted:
|
||||||
@ -164,6 +173,15 @@ class TaskOrder(Base, mixins.TimestampsMixin):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def balance(self):
|
def balance(self):
|
||||||
|
# Faking the remaining balance using the stubbed reporting data for A-Wing & B-Wing
|
||||||
|
if (
|
||||||
|
self.portfolio_name in MockReportingProvider.REPORT_FIXTURE_MAP
|
||||||
|
and self.is_active
|
||||||
|
):
|
||||||
|
return self.budget - app.csp.reports.get_total_spending(self.portfolio)
|
||||||
|
# Faking an almost fully spent TO if the TO is expired
|
||||||
|
if self.is_expired:
|
||||||
|
return random.randrange(300) / 100 # nosec
|
||||||
# TODO: somehow calculate the remaining balance. For now, assume $0 spent
|
# TODO: somehow calculate the remaining balance. For now, assume $0 spent
|
||||||
return self.budget
|
return self.budget
|
||||||
|
|
||||||
|
@ -43,28 +43,6 @@ dod_ids = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def create_demo_portfolio(name, data):
|
|
||||||
try:
|
|
||||||
portfolio_owner = Users.get_or_create_by_dod_id("2345678901") # Amanda
|
|
||||||
# auditor = Users.get_by_dod_id("3453453453") # Sally
|
|
||||||
except NotFoundError:
|
|
||||||
print(
|
|
||||||
"Could not find demo users; will not create demo portfolio {}".format(name)
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
portfolio = Portfolios.create(portfolio_owner, name=name)
|
|
||||||
|
|
||||||
for mock_application in data["applications"]:
|
|
||||||
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)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
|
|
||||||
def remove_sample_data(all_users=False):
|
def remove_sample_data(all_users=False):
|
||||||
query = db.session.query(User)
|
query = db.session.query(User)
|
||||||
if not all_users:
|
if not all_users:
|
||||||
@ -123,13 +101,7 @@ def remove_sample_data(all_users=False):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
config = make_config({"DISABLE_CRL_CHECK": True})
|
config = make_config({"DISABLE_CRL_CHECK": True, "DEBUG": False})
|
||||||
app = make_app(config)
|
app = make_app(config)
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
remove_sample_data()
|
remove_sample_data()
|
||||||
create_demo_portfolio(
|
|
||||||
"Aardvark", MockReportingProvider.REPORT_FIXTURE_MAP["Aardvark"]
|
|
||||||
)
|
|
||||||
create_demo_portfolio(
|
|
||||||
"Beluga", MockReportingProvider.REPORT_FIXTURE_MAP["Beluga"]
|
|
||||||
)
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from datetime import datetime, timedelta, date
|
from datetime import datetime, timedelta, date
|
||||||
|
import random
|
||||||
|
|
||||||
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)
|
sys.path.append(parent_dir)
|
||||||
@ -20,8 +21,13 @@ from tests.factories import (
|
|||||||
random_future_date,
|
random_future_date,
|
||||||
random_past_date,
|
random_past_date,
|
||||||
random_task_order_number,
|
random_task_order_number,
|
||||||
|
random_service_branch,
|
||||||
)
|
)
|
||||||
from atst.routes.dev import _DEV_USERS as DEV_USERS
|
from atst.routes.dev import _DEV_USERS as DEV_USERS
|
||||||
|
from atst.domain.csp.reports import MockReportingProvider
|
||||||
|
from atst.models.application import Application
|
||||||
|
from atst.domain.environments import Environments
|
||||||
|
|
||||||
|
|
||||||
PORTFOLIO_USERS = [
|
PORTFOLIO_USERS = [
|
||||||
{
|
{
|
||||||
@ -83,7 +89,7 @@ PORTFOLIO_INVITED_USERS = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def seed_db():
|
def get_users():
|
||||||
users = []
|
users = []
|
||||||
for dev_user in DEV_USERS.values():
|
for dev_user in DEV_USERS.values():
|
||||||
try:
|
try:
|
||||||
@ -92,166 +98,166 @@ def seed_db():
|
|||||||
user = Users.get_by_dod_id(dev_user["dod_id"])
|
user = Users.get_by_dod_id(dev_user["dod_id"])
|
||||||
|
|
||||||
users.append(user)
|
users.append(user)
|
||||||
|
return users
|
||||||
|
|
||||||
amanda = Users.get_by_dod_id("2345678901")
|
|
||||||
|
|
||||||
# create Portfolios for all users that have funding and are not expiring soon
|
def add_members_to_portfolio(portfolio, users):
|
||||||
for user in users:
|
for user in users:
|
||||||
portfolio = Portfolios.create(
|
|
||||||
user, name="{}'s portfolio (not expiring)".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)
|
ws_role = Portfolios.create_member(
|
||||||
|
portfolio.owner, portfolio, portfolio_role
|
||||||
|
)
|
||||||
db.session.refresh(ws_role)
|
db.session.refresh(ws_role)
|
||||||
PortfolioRoles.enable(ws_role)
|
PortfolioRoles.enable(ws_role)
|
||||||
|
|
||||||
for portfolio_role in PORTFOLIO_INVITED_USERS:
|
for portfolio_role in PORTFOLIO_INVITED_USERS:
|
||||||
ws_role = Portfolios.create_member(user, portfolio, portfolio_role)
|
ws_role = Portfolios.create_member(
|
||||||
|
portfolio.owner, portfolio, portfolio_role
|
||||||
|
)
|
||||||
invitation = InvitationFactory.build(
|
invitation = InvitationFactory.build(
|
||||||
portfolio_role=ws_role, status=portfolio_role["status"]
|
portfolio_role=ws_role, status=portfolio_role["status"]
|
||||||
)
|
)
|
||||||
db.session.add(invitation)
|
db.session.add(invitation)
|
||||||
|
|
||||||
[old_expired_start, expired_start, expired_end] = sorted(
|
db.session.commit()
|
||||||
[
|
|
||||||
random_past_date(year_max=3, year_min=2),
|
|
||||||
random_past_date(year_max=2, year_min=1),
|
|
||||||
random_past_date(year_max=1, year_min=1),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
[
|
|
||||||
first_active_start,
|
|
||||||
second_active_start,
|
|
||||||
first_active_end,
|
|
||||||
second_active_end,
|
|
||||||
] = sorted(
|
|
||||||
[
|
|
||||||
expired_end,
|
|
||||||
random_past_date(year_max=1, year_min=1),
|
|
||||||
random_future_date(year_min=0, year_max=1),
|
|
||||||
random_future_date(year_min=1, year_max=1),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
date_ranges = [
|
|
||||||
(old_expired_start, expired_start),
|
def add_active_task_order(portfolio, active_exp_days=90, clin_01=None, clin_03=None):
|
||||||
(expired_start, expired_end),
|
start = random_past_date(year_max=1, year_min=1)
|
||||||
(first_active_start, first_active_end),
|
default_kwargs = {
|
||||||
(second_active_start, second_active_end),
|
"start_date": start,
|
||||||
]
|
"end_date": (date.today() + timedelta(days=active_exp_days)),
|
||||||
for (start_date, end_date) in date_ranges:
|
"number": random_task_order_number(),
|
||||||
|
"portfolio": portfolio,
|
||||||
|
"clin_02": 0,
|
||||||
|
"clin_04": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
if clin_01:
|
||||||
|
default_kwargs["clin_01"] = clin_01
|
||||||
|
if clin_03:
|
||||||
|
default_kwargs["clin_03"] = clin_03
|
||||||
|
|
||||||
|
task_order = TaskOrderFactory.build(**default_kwargs)
|
||||||
|
db.session.add(task_order)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def add_expired_task_order(portfolio):
|
||||||
|
start = random_past_date(year_max=3, year_min=2)
|
||||||
task_order = TaskOrderFactory.build(
|
task_order = TaskOrderFactory.build(
|
||||||
start_date=start_date,
|
start_date=start,
|
||||||
end_date=end_date,
|
end_date=(start + timedelta(days=90)),
|
||||||
number=random_task_order_number(),
|
number=random_task_order_number(),
|
||||||
portfolio=portfolio,
|
portfolio=portfolio,
|
||||||
)
|
)
|
||||||
db.session.add(task_order)
|
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()
|
db.session.commit()
|
||||||
|
|
||||||
Applications.create(
|
|
||||||
user,
|
def add_pending_task_order(portfolio):
|
||||||
|
start_date = random_future_date(year_min=1, year_max=2)
|
||||||
|
|
||||||
|
task_order = TaskOrderFactory.build(
|
||||||
|
start_date=start_date,
|
||||||
|
end_date=(start_date + timedelta(days=90)),
|
||||||
|
number=random_task_order_number(),
|
||||||
portfolio=portfolio,
|
portfolio=portfolio,
|
||||||
name="First Application",
|
|
||||||
description="This is our first application.",
|
|
||||||
environment_names=["dev", "staging", "prod"],
|
|
||||||
)
|
)
|
||||||
|
db.session.add(task_order)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def add_applications_to_portfolio(portfolio, applications):
|
||||||
|
for application in applications:
|
||||||
|
Applications.create(
|
||||||
|
portfolio.owner,
|
||||||
|
portfolio=portfolio,
|
||||||
|
name=application["name"],
|
||||||
|
description=application["description"],
|
||||||
|
environment_names=application["environments"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def create_demo_portfolio(name, data):
|
||||||
|
try:
|
||||||
|
portfolio_owner = Users.get_or_create_by_dod_id("2345678901") # Amanda
|
||||||
|
# auditor = Users.get_by_dod_id("3453453453") # Sally
|
||||||
|
except NotFoundError:
|
||||||
|
print(
|
||||||
|
"Could not find demo users; will not create demo portfolio {}".format(name)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
portfolio = Portfolios.create(
|
||||||
|
portfolio_owner, name=name, defense_component=random_service_branch()
|
||||||
|
)
|
||||||
|
clin_01 = data["budget"] * 0.8
|
||||||
|
clin_03 = data["budget"] * 0.2
|
||||||
|
|
||||||
|
add_active_task_order(portfolio, clin_01=clin_01, clin_03=clin_03)
|
||||||
|
add_expired_task_order(portfolio)
|
||||||
|
add_pending_task_order(portfolio)
|
||||||
|
add_members_to_portfolio(portfolio, users=get_users())
|
||||||
|
|
||||||
|
for mock_application in data["applications"]:
|
||||||
|
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)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def seed_db():
|
||||||
|
users = get_users()
|
||||||
|
amanda = Users.get_by_dod_id("2345678901")
|
||||||
|
application_info = [
|
||||||
|
{
|
||||||
|
"name": "First Application",
|
||||||
|
"description": "This is our first application",
|
||||||
|
"environments": ["dev", "staging", "prod"],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
# Create Portfolios for Amanda with mocked reporting data
|
||||||
|
create_demo_portfolio("A-Wing", MockReportingProvider.REPORT_FIXTURE_MAP["A-Wing"])
|
||||||
|
create_demo_portfolio("B-Wing", MockReportingProvider.REPORT_FIXTURE_MAP["B-Wing"])
|
||||||
|
|
||||||
# Create Portfolio for Amanda with TO that is expiring soon and does not have another TO
|
# Create Portfolio for Amanda with TO that is expiring soon and does not have another TO
|
||||||
unfunded_portfolio = Portfolios.create(
|
unfunded_portfolio = Portfolios.create(
|
||||||
amanda, name="{}'s portfolio (expiring and unfunded)".format(amanda.first_name)
|
amanda, name="TIE Interceptor", defense_component=random_service_branch()
|
||||||
)
|
|
||||||
|
|
||||||
[past_date_1, past_date_2, past_date_3, future_date] = sorted(
|
|
||||||
[
|
|
||||||
random_past_date(year_max=3, year_min=2),
|
|
||||||
random_past_date(year_max=2, year_min=1),
|
|
||||||
random_past_date(year_max=1, year_min=1),
|
|
||||||
(date.today() + timedelta(days=20)),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
date_ranges = [
|
|
||||||
(past_date_1, past_date_2),
|
|
||||||
(past_date_2, past_date_3),
|
|
||||||
(past_date_3, future_date),
|
|
||||||
]
|
|
||||||
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=unfunded_portfolio,
|
|
||||||
)
|
|
||||||
db.session.add(task_order)
|
|
||||||
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
Applications.create(
|
|
||||||
amanda,
|
|
||||||
portfolio=unfunded_portfolio,
|
|
||||||
name="First Application",
|
|
||||||
description="This is our first application.",
|
|
||||||
environment_names=["dev", "staging", "prod"],
|
|
||||||
)
|
)
|
||||||
|
add_active_task_order(unfunded_portfolio, active_exp_days=20)
|
||||||
|
add_expired_task_order(unfunded_portfolio)
|
||||||
|
add_members_to_portfolio(unfunded_portfolio, users=users)
|
||||||
|
add_applications_to_portfolio(unfunded_portfolio, application_info)
|
||||||
|
|
||||||
# Create Portfolio for Amanda with TO that is expiring soon and has another TO
|
# Create Portfolio for Amanda with TO that is expiring soon and has another TO
|
||||||
funded_portfolio = Portfolios.create(
|
funded_portfolio = Portfolios.create(
|
||||||
amanda, name="{}'s portfolio (expiring and funded)".format(amanda.first_name)
|
amanda, name="TIE Fighter", defense_component=random_service_branch()
|
||||||
)
|
)
|
||||||
|
add_active_task_order(funded_portfolio, active_exp_days=20)
|
||||||
|
add_expired_task_order(funded_portfolio)
|
||||||
|
add_pending_task_order(funded_portfolio)
|
||||||
|
add_members_to_portfolio(funded_portfolio, users=users)
|
||||||
|
add_applications_to_portfolio(funded_portfolio, application_info)
|
||||||
|
|
||||||
[
|
# create a portfolio 'Y-Wing' for each user
|
||||||
past_date_1,
|
for user in users:
|
||||||
past_date_2,
|
portfolio = Portfolios.create(
|
||||||
past_date_3,
|
user, name="Y-Wing", defense_component=random_service_branch()
|
||||||
past_date_4,
|
|
||||||
future_date_1,
|
|
||||||
future_date_2,
|
|
||||||
] = sorted(
|
|
||||||
[
|
|
||||||
random_past_date(year_max=3, year_min=2),
|
|
||||||
random_past_date(year_max=2, year_min=1),
|
|
||||||
random_past_date(year_max=1, year_min=1),
|
|
||||||
random_past_date(year_max=1, year_min=1),
|
|
||||||
(date.today() + timedelta(days=20)),
|
|
||||||
random_future_date(year_min=0, year_max=1),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
date_ranges = [
|
|
||||||
(past_date_1, past_date_2),
|
|
||||||
(past_date_2, past_date_3),
|
|
||||||
(past_date_3, future_date_1),
|
|
||||||
(past_date_4, future_date_2),
|
|
||||||
]
|
|
||||||
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=funded_portfolio,
|
|
||||||
)
|
|
||||||
db.session.add(task_order)
|
|
||||||
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
Applications.create(
|
|
||||||
amanda,
|
|
||||||
portfolio=funded_portfolio,
|
|
||||||
name="First Application",
|
|
||||||
description="This is our first application.",
|
|
||||||
environment_names=["dev", "staging", "prod"],
|
|
||||||
)
|
)
|
||||||
|
add_members_to_portfolio(portfolio, users=users)
|
||||||
|
add_active_task_order(portfolio)
|
||||||
|
add_expired_task_order(portfolio)
|
||||||
|
add_pending_task_order(portfolio)
|
||||||
|
add_applications_to_portfolio(portfolio, application_info)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
config = make_config({"DISABLE_CRL_CHECK": True})
|
config = make_config({"DISABLE_CRL_CHECK": True, "DEBUG": False})
|
||||||
app = make_app(config)
|
app = make_app(config)
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
seed_db()
|
seed_db()
|
||||||
|
@ -27,10 +27,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class='portfolio-header__budget--amount'>
|
<div class='portfolio-header__budget--amount'>
|
||||||
<span class='portfolio-header__budget--dollars'>
|
<span class='portfolio-header__budget--dollars'>
|
||||||
{{ portfolio.task_orders | selectattr('is_active') | sum(attribute='budget') | justDollars }}
|
{{ portfolio.task_orders | selectattr('is_active') | sum(attribute='balance') | justDollars }}
|
||||||
</span>
|
</span>
|
||||||
<span class='portfolio-header__budget--cents'>
|
<span class='portfolio-header__budget--cents'>
|
||||||
.{{ portfolio.task_orders | selectattr('is_active') | sum(attribute='budget') | justCents }}
|
.{{ portfolio.task_orders | selectattr('is_active') | sum(attribute='balance') | justCents }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -81,7 +81,7 @@ def test_portfolio_reports(client, user_session):
|
|||||||
|
|
||||||
|
|
||||||
def test_portfolio_reports_with_mock_portfolio(client, user_session):
|
def test_portfolio_reports_with_mock_portfolio(client, user_session):
|
||||||
portfolio = PortfolioFactory.create(name="Aardvark")
|
portfolio = PortfolioFactory.create(name="A-Wing")
|
||||||
user_session(portfolio.owner)
|
user_session(portfolio.owner)
|
||||||
response = client.get(
|
response = client.get(
|
||||||
url_for("portfolios.portfolio_reports", portfolio_id=portfolio.id)
|
url_for("portfolios.portfolio_reports", portfolio_id=portfolio.id)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user