Merge pull request #884 from dod-ccpo/to-funding-statuses
Funding page Task Order statuses
This commit is contained in:
commit
0bd9d4bbb6
@ -2,7 +2,7 @@ from flask import current_app as app
|
||||
|
||||
from atst.database import db
|
||||
from atst.models.clin import CLIN
|
||||
from atst.models.task_order import TaskOrder
|
||||
from atst.models.task_order import TaskOrder, SORT_ORDERING
|
||||
from . import BaseDomainClass
|
||||
|
||||
|
||||
@ -98,3 +98,10 @@ class TaskOrders(BaseDomainClass):
|
||||
if not app.config.get("CLASSIFIED"):
|
||||
section_list["funding"] = TaskOrders.UNCLASSIFIED_FUNDING
|
||||
return section_list
|
||||
|
||||
@classmethod
|
||||
def sort(cls, task_orders: [TaskOrder]) -> [TaskOrder]:
|
||||
# Sorts a list of task orders on two keys: status (primary) and time_created (secondary)
|
||||
by_time_created = sorted(task_orders, key=lambda to: to.time_created)
|
||||
by_status = sorted(by_time_created, key=lambda to: SORT_ORDERING.get(to.status))
|
||||
return by_status
|
||||
|
@ -1,5 +1,4 @@
|
||||
from enum import Enum
|
||||
from datetime import date
|
||||
|
||||
from sqlalchemy import Column, DateTime, ForeignKey, String
|
||||
from sqlalchemy.ext.hybrid import hybrid_property
|
||||
@ -8,13 +7,23 @@ from werkzeug.datastructures import FileStorage
|
||||
|
||||
from atst.models import Attachment, Base, mixins, types
|
||||
from atst.models.clin import JEDICLINType
|
||||
from atst.utils.clock import Clock
|
||||
|
||||
|
||||
class Status(Enum):
|
||||
STARTED = "Started"
|
||||
PENDING = "Pending"
|
||||
DRAFT = "Draft"
|
||||
ACTIVE = "Active"
|
||||
UPCOMING = "Upcoming"
|
||||
EXPIRED = "Expired"
|
||||
UNSIGNED = "Not signed"
|
||||
|
||||
|
||||
SORT_ORDERING = {
|
||||
status: order
|
||||
for (order, status) in enumerate(
|
||||
[Status.DRAFT, Status.ACTIVE, Status.UPCOMING, Status.EXPIRED, Status.UNSIGNED]
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class TaskOrder(Base, mixins.TimestampsMixin):
|
||||
@ -62,28 +71,41 @@ class TaskOrder(Base, mixins.TimestampsMixin):
|
||||
def is_expired(self):
|
||||
return self.status == Status.EXPIRED
|
||||
|
||||
@property
|
||||
def is_completed(self):
|
||||
return all([self.pdf, self.number, len(self.clins)])
|
||||
|
||||
@property
|
||||
def is_signed(self):
|
||||
return self.signed_at is not None
|
||||
|
||||
@property
|
||||
def status(self):
|
||||
# TODO: fix task order -- implement correctly using CLINs
|
||||
# Faked for display purposes
|
||||
return Status.ACTIVE
|
||||
today = Clock.today()
|
||||
|
||||
if not self.is_completed and not self.is_signed:
|
||||
return Status.DRAFT
|
||||
elif self.is_completed and not self.is_signed:
|
||||
return Status.UNSIGNED
|
||||
elif today < self.start_date:
|
||||
return Status.UPCOMING
|
||||
elif today >= self.end_date:
|
||||
return Status.EXPIRED
|
||||
elif self.start_date <= today < self.end_date:
|
||||
return Status.ACTIVE
|
||||
|
||||
@property
|
||||
def start_date(self):
|
||||
# TODO: fix task order -- reimplement using CLINs
|
||||
# Faked for display purposes
|
||||
return date.today()
|
||||
return min((c.start_date for c in self.clins), default=self.time_created.date())
|
||||
|
||||
@property
|
||||
def end_date(self):
|
||||
# TODO: fix task order -- reimplement using CLINs
|
||||
# Faked for display purposes
|
||||
return date.today()
|
||||
return max((c.end_date for c in self.clins), default=None)
|
||||
|
||||
@property
|
||||
def days_to_expiration(self):
|
||||
if self.end_date:
|
||||
return (self.end_date - date.today()).days
|
||||
return (self.end_date - Clock.today()).days
|
||||
|
||||
@property
|
||||
def total_obligated_funds(self):
|
||||
|
@ -1,13 +1,11 @@
|
||||
from collections import defaultdict
|
||||
|
||||
from flask import g, render_template
|
||||
|
||||
from . import task_orders_bp
|
||||
from atst.domain.authz.decorator import user_can_access_decorator as user_can
|
||||
from atst.domain.portfolios import Portfolios
|
||||
from atst.domain.task_orders import TaskOrders
|
||||
from atst.models.task_order import Status
|
||||
from atst.models import Permissions
|
||||
from atst.models.task_order import Status as TaskOrderStatus
|
||||
|
||||
|
||||
@task_orders_bp.route("/task_orders/<task_order_id>")
|
||||
@ -34,19 +32,16 @@ def review_task_order(task_order_id):
|
||||
@user_can(Permissions.VIEW_PORTFOLIO_FUNDING, message="view portfolio funding")
|
||||
def portfolio_funding(portfolio_id):
|
||||
portfolio = Portfolios.get(g.current_user, portfolio_id)
|
||||
task_orders_by_status = defaultdict(list)
|
||||
|
||||
for task_order in portfolio.task_orders:
|
||||
task_orders_by_status[task_order.status].append(task_order)
|
||||
|
||||
active_task_orders = task_orders_by_status.get(TaskOrderStatus.ACTIVE, [])
|
||||
|
||||
task_orders = TaskOrders.sort(portfolio.task_orders)
|
||||
label_colors = {
|
||||
Status.DRAFT: "warning",
|
||||
Status.ACTIVE: "success",
|
||||
Status.UPCOMING: "info",
|
||||
Status.EXPIRED: "error",
|
||||
Status.UNSIGNED: "purple",
|
||||
}
|
||||
return render_template(
|
||||
"portfolios/task_orders/index.html",
|
||||
pending_task_orders=(
|
||||
task_orders_by_status.get(TaskOrderStatus.STARTED, [])
|
||||
+ task_orders_by_status.get(TaskOrderStatus.PENDING, [])
|
||||
),
|
||||
active_task_orders=active_task_orders,
|
||||
expired_task_orders=task_orders_by_status.get(TaskOrderStatus.EXPIRED, []),
|
||||
task_orders=task_orders,
|
||||
label_colors=label_colors,
|
||||
)
|
||||
|
11
atst/utils/clock.py
Normal file
11
atst/utils/clock.py
Normal file
@ -0,0 +1,11 @@
|
||||
import pendulum
|
||||
|
||||
|
||||
class Clock(object):
|
||||
@classmethod
|
||||
def today(cls, tz="UTC"):
|
||||
return pendulum.today(tz=tz).date()
|
||||
|
||||
@classmethod
|
||||
def now(cls, tz="UTC"):
|
||||
return pendulum.now(tz=tz)
|
@ -31,5 +31,8 @@ contract = client.get_contract(contract_number=contract_number, status="Y")
|
||||
|
||||
requested_clins = ",".join(["'0001'", "'0003'", "'1001'", "'1003'", "'2001'", "'2003'"])
|
||||
clins = client.get_clins(
|
||||
record_key=contract_number, duns_number="", cage_code="1U305", clins=requested_clins
|
||||
record_key=contract_number,
|
||||
duns_number="",
|
||||
cage_code="1U305",
|
||||
with_clins=requested_clins,
|
||||
)
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Add root application dir to the python path
|
||||
import os
|
||||
import sys
|
||||
from datetime import timedelta, date
|
||||
from datetime import timedelta, date, timedelta
|
||||
import random
|
||||
from faker import Faker
|
||||
|
||||
@ -31,6 +31,7 @@ from tests.factories import (
|
||||
random_service_branch,
|
||||
random_task_order_number,
|
||||
TaskOrderFactory,
|
||||
CLINFactory,
|
||||
)
|
||||
|
||||
fake = Faker()
|
||||
@ -160,16 +161,28 @@ def add_members_to_portfolio(portfolio):
|
||||
|
||||
|
||||
def add_task_orders_to_portfolio(portfolio):
|
||||
# TODO: after CLINs are implemented, vary the start/end dates of TOs
|
||||
create_task_order(portfolio)
|
||||
create_task_order(portfolio)
|
||||
create_task_order(portfolio)
|
||||
today = date.today()
|
||||
future = today + timedelta(days=100)
|
||||
yesterday = today - timedelta(days=1)
|
||||
|
||||
draft_to = TaskOrderFactory.build(portfolio=portfolio, pdf=None)
|
||||
unsigned_to = TaskOrderFactory.build(portfolio=portfolio)
|
||||
upcoming_to = TaskOrderFactory.build(portfolio=portfolio, signed_at=yesterday)
|
||||
expired_to = TaskOrderFactory.build(portfolio=portfolio, signed_at=yesterday)
|
||||
active_to = TaskOrderFactory.build(portfolio=portfolio, signed_at=yesterday)
|
||||
|
||||
def create_task_order(portfolio):
|
||||
# TODO: after CLINs are implemented add them to TO
|
||||
task_order = TaskOrderFactory.build(portfolio=portfolio)
|
||||
db.session.add(task_order)
|
||||
clins = [
|
||||
CLINFactory.build(task_order=unsigned_to, start_date=today, end_date=today),
|
||||
CLINFactory.build(task_order=upcoming_to, start_date=future, end_date=future),
|
||||
CLINFactory.build(
|
||||
task_order=expired_to, start_date=yesterday, end_date=yesterday
|
||||
),
|
||||
CLINFactory.build(task_order=active_to, start_date=yesterday, end_date=future),
|
||||
]
|
||||
|
||||
task_orders = [draft_to, unsigned_to, upcoming_to, expired_to, active_to]
|
||||
|
||||
db.session.add_all(task_orders + clins)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
|
@ -33,4 +33,8 @@
|
||||
&.label--success {
|
||||
background-color: $color-green;
|
||||
}
|
||||
|
||||
&.label--purple {
|
||||
background-color: $color-purple;
|
||||
}
|
||||
}
|
||||
|
@ -73,6 +73,9 @@
|
||||
.task-order-card .label {
|
||||
font-size: $small-font-size;
|
||||
margin-right: 2 * $gap;
|
||||
min-width: 7rem;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.task-order-card__buttons .usa-button {
|
||||
|
@ -45,7 +45,7 @@
|
||||
{% for task_order in task_orders %}
|
||||
<div class="card task-order-card">
|
||||
<div class="card__status">
|
||||
<span class='label label--{{ label }}'>{{ task_order.display_status }}</span>
|
||||
<span class='label label--{{ label_colors[task_order.status] }}'>{{ task_order.display_status }}</span>
|
||||
{{ TaskOrderDate(task_order) }}
|
||||
<span class="card__status-spacer"></span>
|
||||
<span class="card__button">
|
||||
@ -70,7 +70,9 @@
|
||||
|
||||
<div class="portfolio-funding">
|
||||
|
||||
{% if not active_task_orders and not pending_task_orders %}
|
||||
{% if task_orders %}
|
||||
{{ TaskOrderList(task_orders) }}
|
||||
{% else %}
|
||||
{{ EmptyState(
|
||||
'This portfolio doesn’t have any active or pending task orders.',
|
||||
action_label='Add a New Task Order',
|
||||
@ -78,18 +80,6 @@
|
||||
icon='cloud',
|
||||
) }}
|
||||
{% endif %}
|
||||
|
||||
{% if pending_task_orders %}
|
||||
{{ TaskOrderList(pending_task_orders, label='warning') }}
|
||||
{% endif %}
|
||||
|
||||
{% if active_task_orders %}
|
||||
{{ TaskOrderList(active_task_orders, label='success') }}
|
||||
{% endif %}
|
||||
|
||||
{% if expired_task_orders %}
|
||||
{{ TaskOrderList(expired_task_orders, label='error') }}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
@ -1,19 +1,78 @@
|
||||
import pytest
|
||||
from datetime import date
|
||||
from datetime import date, timedelta
|
||||
from decimal import Decimal
|
||||
|
||||
from atst.domain.task_orders import TaskOrders, TaskOrderError
|
||||
from atst.domain.exceptions import UnauthorizedError
|
||||
from atst.domain.permission_sets import PermissionSets
|
||||
from atst.domain.portfolio_roles import PortfolioRoles
|
||||
from atst.domain.task_orders import TaskOrders
|
||||
from atst.models.attachment import Attachment
|
||||
from tests.factories import TaskOrderFactory, CLINFactory, PortfolioFactory
|
||||
|
||||
from tests.factories import (
|
||||
TaskOrderFactory,
|
||||
UserFactory,
|
||||
PortfolioRoleFactory,
|
||||
PortfolioFactory,
|
||||
)
|
||||
|
||||
def test_task_order_sorting():
|
||||
"""
|
||||
Task orders should be listed first by status, and then by time_created.
|
||||
"""
|
||||
|
||||
today = date.today()
|
||||
yesterday = today - timedelta(days=1)
|
||||
future = today + timedelta(days=100)
|
||||
|
||||
task_orders = [
|
||||
# Draft
|
||||
TaskOrderFactory.create(pdf=None),
|
||||
TaskOrderFactory.create(pdf=None),
|
||||
TaskOrderFactory.create(pdf=None),
|
||||
# Active
|
||||
TaskOrderFactory.create(
|
||||
signed_at=yesterday,
|
||||
clins=[CLINFactory.create(start_date=yesterday, end_date=future)],
|
||||
),
|
||||
TaskOrderFactory.create(
|
||||
signed_at=yesterday,
|
||||
clins=[CLINFactory.create(start_date=yesterday, end_date=future)],
|
||||
),
|
||||
TaskOrderFactory.create(
|
||||
signed_at=yesterday,
|
||||
clins=[CLINFactory.create(start_date=yesterday, end_date=future)],
|
||||
),
|
||||
# Upcoming
|
||||
TaskOrderFactory.create(
|
||||
signed_at=yesterday,
|
||||
clins=[CLINFactory.create(start_date=future, end_date=future)],
|
||||
),
|
||||
TaskOrderFactory.create(
|
||||
signed_at=yesterday,
|
||||
clins=[CLINFactory.create(start_date=future, end_date=future)],
|
||||
),
|
||||
TaskOrderFactory.create(
|
||||
signed_at=yesterday,
|
||||
clins=[CLINFactory.create(start_date=future, end_date=future)],
|
||||
),
|
||||
# Expired
|
||||
TaskOrderFactory.create(
|
||||
signed_at=yesterday,
|
||||
clins=[CLINFactory.create(start_date=yesterday, end_date=yesterday)],
|
||||
),
|
||||
TaskOrderFactory.create(
|
||||
signed_at=yesterday,
|
||||
clins=[CLINFactory.create(start_date=yesterday, end_date=yesterday)],
|
||||
),
|
||||
TaskOrderFactory.create(
|
||||
signed_at=yesterday,
|
||||
clins=[CLINFactory.create(start_date=yesterday, end_date=yesterday)],
|
||||
),
|
||||
# Unsigned
|
||||
TaskOrderFactory.create(
|
||||
clins=[CLINFactory.create(start_date=today, end_date=today)]
|
||||
),
|
||||
TaskOrderFactory.create(
|
||||
clins=[CLINFactory.create(start_date=today, end_date=today)]
|
||||
),
|
||||
TaskOrderFactory.create(
|
||||
clins=[CLINFactory.create(start_date=today, end_date=today)]
|
||||
),
|
||||
]
|
||||
|
||||
assert TaskOrders.sort(task_orders) == task_orders
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="Need to reimplement after new TO form is created")
|
||||
@ -118,7 +177,9 @@ def test_update_adds_clins(pdf_upload):
|
||||
|
||||
|
||||
def test_update_does_not_duplicate_clins(pdf_upload):
|
||||
task_order = TaskOrderFactory.create(number="3453453456", clins=["123", "456"])
|
||||
task_order = TaskOrderFactory.create(
|
||||
number="3453453456", create_clins=["123", "456"]
|
||||
)
|
||||
clins = [
|
||||
{
|
||||
"jedi_clin_type": "JEDI_CLIN_1",
|
||||
|
@ -272,13 +272,14 @@ class TaskOrderFactory(Base):
|
||||
portfolio = factory.SubFactory(PortfolioFactory)
|
||||
number = factory.LazyFunction(random_task_order_number)
|
||||
creator = factory.SubFactory(UserFactory)
|
||||
_pdf = factory.SubFactory(AttachmentFactory)
|
||||
|
||||
@classmethod
|
||||
def _create(cls, model_class, *args, **kwargs):
|
||||
with_clins = kwargs.pop("clins", [])
|
||||
create_clins = kwargs.pop("create_clins", [])
|
||||
task_order = super()._create(model_class, *args, **kwargs)
|
||||
|
||||
for clin in with_clins:
|
||||
for clin in create_clins:
|
||||
CLINFactory.create(task_order=task_order, number=clin)
|
||||
|
||||
return task_order
|
||||
@ -293,7 +294,7 @@ class CLINFactory(Base):
|
||||
start_date = datetime.date.today()
|
||||
end_date = factory.LazyFunction(random_future_date)
|
||||
obligated_amount = random.randint(100, 999999)
|
||||
jedi_clin_type = random.choice([e.value for e in clin.JEDICLINType])
|
||||
jedi_clin_type = random.choice(list(clin.JEDICLINType))
|
||||
|
||||
|
||||
class NotificationRecipientFactory(Base):
|
||||
|
@ -1,40 +1,120 @@
|
||||
from werkzeug.datastructures import FileStorage
|
||||
import pytest, datetime
|
||||
import pytest
|
||||
from datetime import date
|
||||
from unittest.mock import patch, PropertyMock
|
||||
import pendulum
|
||||
|
||||
from atst.models import *
|
||||
from atst.models.clin import JEDICLINType
|
||||
from atst.models.task_order import TaskOrder, Status
|
||||
|
||||
from tests.factories import (
|
||||
CLINFactory,
|
||||
random_future_date,
|
||||
random_past_date,
|
||||
TaskOrderFactory,
|
||||
)
|
||||
from tests.factories import CLINFactory, TaskOrderFactory
|
||||
from tests.mocks import PDF_FILENAME
|
||||
|
||||
|
||||
def test_period_of_performance_is_first_to_last_clin():
|
||||
start_date = date(2019, 6, 6)
|
||||
end_date = date(2020, 6, 6)
|
||||
|
||||
intermediate_start_date = date(2019, 7, 1)
|
||||
intermediate_end_date = date(2020, 3, 1)
|
||||
|
||||
task_order = TaskOrderFactory.create(
|
||||
clins=[
|
||||
CLINFactory.create(
|
||||
start_date=intermediate_start_date, end_date=intermediate_end_date
|
||||
),
|
||||
CLINFactory.create(start_date=start_date, end_date=intermediate_end_date),
|
||||
CLINFactory.create(
|
||||
start_date=intermediate_start_date, end_date=intermediate_end_date
|
||||
),
|
||||
CLINFactory.create(start_date=intermediate_start_date, end_date=end_date),
|
||||
CLINFactory.create(
|
||||
start_date=intermediate_start_date, end_date=intermediate_end_date
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
assert task_order.start_date == start_date
|
||||
assert task_order.end_date == end_date
|
||||
|
||||
|
||||
def test_task_order_completed():
|
||||
assert TaskOrderFactory.create(clins=[CLINFactory.create()]).is_completed
|
||||
assert not TaskOrderFactory.create().is_completed
|
||||
assert not TaskOrderFactory.create(clins=[]).is_completed
|
||||
assert not TaskOrderFactory.create(number=None).is_completed
|
||||
|
||||
|
||||
class TestTaskOrderStatus:
|
||||
@pytest.mark.skip(reason="Reimplement after adding CLINs")
|
||||
def test_started_status(self):
|
||||
@patch("atst.models.TaskOrder.is_completed", new_callable=PropertyMock)
|
||||
@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()
|
||||
assert to.status == Status.STARTED
|
||||
is_signed.return_value = False
|
||||
is_completed.return_value = False
|
||||
|
||||
@pytest.mark.skip(reason="See if still needed after implementing CLINs")
|
||||
def test_pending_status(self):
|
||||
to = TaskOrder(number="42")
|
||||
assert to.status == Status.PENDING
|
||||
assert to.status == Status.DRAFT
|
||||
|
||||
@pytest.mark.skip(reason="See if still needed after implementing CLINs")
|
||||
def test_active_status(self):
|
||||
to = TaskOrder(number="42")
|
||||
@patch("atst.models.TaskOrder.end_date", new_callable=PropertyMock)
|
||||
@patch("atst.models.TaskOrder.start_date", new_callable=PropertyMock)
|
||||
@patch("atst.models.TaskOrder.is_completed", new_callable=PropertyMock)
|
||||
@patch("atst.models.TaskOrder.is_signed", new_callable=PropertyMock)
|
||||
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()
|
||||
|
||||
start_date.return_value = today.subtract(days=1)
|
||||
end_date.return_value = today.add(days=1)
|
||||
is_signed.return_value = True
|
||||
is_completed.return_value = True
|
||||
|
||||
# Its status should be active
|
||||
assert to.status == Status.ACTIVE
|
||||
|
||||
@pytest.mark.skip(reason="See if still needed after implementing CLINs")
|
||||
def test_expired_status(self):
|
||||
to = TaskOrder(number="42")
|
||||
@patch("atst.models.TaskOrder.end_date", new_callable=PropertyMock)
|
||||
@patch("atst.models.TaskOrder.start_date", new_callable=PropertyMock)
|
||||
@patch("atst.models.TaskOrder.is_completed", new_callable=PropertyMock)
|
||||
@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()
|
||||
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
|
||||
is_completed.return_value = True
|
||||
|
||||
# Its status should be upcoming
|
||||
assert to.status == Status.UPCOMING
|
||||
|
||||
@patch("atst.models.TaskOrder.start_date", new_callable=PropertyMock)
|
||||
@patch("atst.models.TaskOrder.end_date", new_callable=PropertyMock)
|
||||
@patch("atst.models.TaskOrder.is_completed", new_callable=PropertyMock)
|
||||
@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()
|
||||
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
|
||||
is_completed.return_value = True
|
||||
|
||||
# Its status should be expired
|
||||
assert to.status == Status.EXPIRED
|
||||
|
||||
@patch("atst.models.TaskOrder.is_completed", new_callable=PropertyMock)
|
||||
@patch("atst.models.TaskOrder.is_signed", new_callable=PropertyMock)
|
||||
def test_unsigned_status(self, is_signed, is_completed):
|
||||
# Given that I have a TO that is completed but not signed
|
||||
to = TaskOrder(signed_at=pendulum.now().subtract(days=1))
|
||||
is_completed.return_value = True
|
||||
is_signed.return_value = False
|
||||
|
||||
# Its status should be unsigned
|
||||
assert to.status == Status.UNSIGNED
|
||||
|
||||
|
||||
class TestBudget:
|
||||
def test_total_contract_amount(self):
|
||||
|
@ -100,8 +100,6 @@ def test_portfolio_reports(client, user_session):
|
||||
response = client.get(url_for("portfolios.reports", portfolio_id=portfolio.id))
|
||||
assert response.status_code == 200
|
||||
assert portfolio.name in response.data.decode()
|
||||
expiration_date = task_order.end_date.strftime("%Y-%m-%d")
|
||||
assert expiration_date in response.data.decode()
|
||||
|
||||
|
||||
def test_portfolio_reports_with_mock_portfolio(client, user_session):
|
||||
|
@ -18,7 +18,7 @@ def xml_translated(val):
|
||||
def test_download_summary(client, user_session):
|
||||
user = UserFactory.create()
|
||||
portfolio = PortfolioFactory.create(owner=user)
|
||||
task_order = TaskOrderFactory.create(creator=user, portfolio=portfolio)
|
||||
task_order = TaskOrderFactory.create(creator=user, portfolio=portfolio, _pdf=None)
|
||||
user_session(user)
|
||||
response = client.get(
|
||||
url_for("task_orders.download_summary", task_order_id=task_order.id)
|
||||
|
Loading…
x
Reference in New Issue
Block a user