Merge pull request #867 from dod-ccpo/totals-box

Totals Box
This commit is contained in:
montana-mil 2019-06-05 09:53:15 -04:00 committed by GitHub
commit 15cc01ed39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 105 additions and 12 deletions

View File

@ -0,0 +1,28 @@
"""add jedi clin type to clin table
Revision ID: c19d6129cca1
Revises: 988f8b23fbf6
Create Date: 2019-06-04 11:30:25.283028
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'c19d6129cca1'
down_revision = '988f8b23fbf6'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('clins', sa.Column('jedi_clin_type', sa.Enum('JEDI_CLIN_1', 'JEDI_CLIN_2', 'JEDI_CLIN_3', 'JEDI_CLIN_4', name='jediclintype', native_enum=False), nullable=False))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('clins', 'jedi_clin_type')
# ### end Alembic commands ###

View File

@ -6,7 +6,8 @@ from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from werkzeug.datastructures import FileStorage from werkzeug.datastructures import FileStorage
from atst.models import Attachment, Base, types, mixins from atst.models import Attachment, Base, mixins, types
from atst.models.clin import JEDICLINType
class Status(Enum): class Status(Enum):
@ -33,6 +34,8 @@ class TaskOrder(Base, mixins.TimestampsMixin):
signer_dod_id = Column(String) signer_dod_id = Column(String)
signed_at = Column(DateTime) signed_at = Column(DateTime)
clins = relationship("CLIN")
@hybrid_property @hybrid_property
def pdf(self): def pdf(self):
return self._pdf return self._pdf
@ -83,9 +86,26 @@ class TaskOrder(Base, mixins.TimestampsMixin):
return (self.end_date - date.today()).days return (self.end_date - date.today()).days
@property @property
def total_obligated_funds(self):
total = 0
for clin in self.clins:
if clin.jedi_clin_type in [
JEDICLINType.JEDI_CLIN_1,
JEDICLINType.JEDI_CLIN_3,
]:
total += clin.obligated_amount
return total
@property
def total_contract_amount(self):
total = 0
for clin in self.clins:
total += clin.obligated_amount
return total
@property
# TODO delete when we delete task_order_review flow
def budget(self): def budget(self):
# TODO: fix task order -- reimplement using CLINs
# Faked for display purposes
return 100000 return 100000
@property @property

View File

@ -93,7 +93,7 @@
margin-top: $gap * 2; margin-top: $gap * 2;
} }
.to-sidebar { .totals-box {
padding: $gap * 4; padding: $gap * 4;
padding-top: $gap * 2; padding-top: $gap * 2;
flex-grow: unset; flex-grow: unset;

View File

@ -1,14 +1,14 @@
{% macro TOSidebar() -%} {% macro TotalsBox(task_order) -%}
<div class="col to-sidebar"> <div class="col totals-box">
<div class="h4">Total obligated funds</div> <div class="h4">Total obligated funds</div>
<div class="h3">$500,000</div> <div class="h3">{{ task_order.total_obligated_funds | dollars }}</div>
<div>This is the funding allocated to cloud services. It may be 100% or a portion of the total task order budget.</div> <div>This is the funding allocated to cloud services. It may be 100% or a portion of the total task order budget.</div>
<hr> <hr>
<div class="h4">Total contract amount</div> <div class="h4">Total contract amount</div>
<div class="h3">$800,000</div> <div class="h3">{{ task_order.total_contract_amount | dollars }}</div>
<div>This is the value of all funds obligated for this contract, including -- but not limited to -- funds obligated for the cloud.</div> <div>This is the value of all funds obligated for this contract, including -- but not limited to -- funds obligated for the cloud.</div>
</div> </div>

View File

@ -1,7 +1,7 @@
{% extends 'portfolios/base.html' %} {% extends 'portfolios/base.html' %}
{% from "components/icon.html" import Icon %} {% from "components/icon.html" import Icon %}
{% from "components/to_sidebar.html" import TOSidebar %} {% from "components/totals_box.html" import TotalsBox %}
{% block content %} {% block content %}
@ -83,7 +83,7 @@
<div class="h4">{{ Icon('ok',classes="icon-validation") }}document</div> <div class="h4">{{ Icon('ok',classes="icon-validation") }}document</div>
</div> </div>
{{ TOSidebar() }} {{ TotalsBox(task_order=task_order) }}
</div> </div>

View File

@ -269,6 +269,18 @@ class TaskOrderFactory(Base):
number = factory.LazyFunction(random_task_order_number) number = factory.LazyFunction(random_task_order_number)
class CLINFactory(Base):
class Meta:
model = CLIN
task_order = factory.SubFactory(TaskOrderFactory)
number = factory.LazyFunction(random_task_order_number)
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])
class NotificationRecipientFactory(Base): class NotificationRecipientFactory(Base):
class Meta: class Meta:
model = NotificationRecipient model = NotificationRecipient

View File

@ -1,10 +1,16 @@
from werkzeug.datastructures import FileStorage from werkzeug.datastructures import FileStorage
import pytest, datetime import pytest, datetime
from atst.models.attachment import Attachment from atst.models import *
from atst.models.clin import JEDICLINType
from atst.models.task_order import TaskOrder, Status from atst.models.task_order import TaskOrder, Status
from tests.factories import random_future_date, random_past_date from tests.factories import (
CLINFactory,
random_future_date,
random_past_date,
TaskOrderFactory,
)
from tests.mocks import PDF_FILENAME from tests.mocks import PDF_FILENAME
@ -30,6 +36,33 @@ class TestTaskOrderStatus:
assert to.status == Status.EXPIRED assert to.status == Status.EXPIRED
class TestBudget:
def test_total_contract_amount(self):
to = TaskOrder()
assert to.total_contract_amount == 0
clin1 = CLINFactory(task_order=to, jedi_clin_type=JEDICLINType.JEDI_CLIN_1)
clin2 = CLINFactory(task_order=to, jedi_clin_type=JEDICLINType.JEDI_CLIN_2)
clin3 = CLINFactory(task_order=to, jedi_clin_type=JEDICLINType.JEDI_CLIN_3)
assert (
to.total_contract_amount
== clin1.obligated_amount + clin2.obligated_amount + clin3.obligated_amount
)
def test_total_obligated_funds(self):
to = TaskOrder()
clin4 = CLINFactory(task_order=to, jedi_clin_type=JEDICLINType.JEDI_CLIN_4)
assert to.total_obligated_funds == 0
clin1 = CLINFactory(task_order=to, jedi_clin_type=JEDICLINType.JEDI_CLIN_1)
clin2 = CLINFactory(task_order=to, jedi_clin_type=JEDICLINType.JEDI_CLIN_2)
clin3 = CLINFactory(task_order=to, jedi_clin_type=JEDICLINType.JEDI_CLIN_3)
assert (
to.total_obligated_funds == clin1.obligated_amount + clin3.obligated_amount
)
class TestPDF: class TestPDF:
def test_setting_pdf_with_attachment(self): def test_setting_pdf_with_attachment(self):
to = TaskOrder() to = TaskOrder()