Merge pull request #629 from dod-ccpo/funding-header
Add Funding Through to Portfolio Header
This commit is contained in:
commit
a1b1905750
@ -19,6 +19,16 @@ def dollars(value):
|
|||||||
return "${:,.2f}".format(numberValue)
|
return "${:,.2f}".format(numberValue)
|
||||||
|
|
||||||
|
|
||||||
|
def justDollars(value):
|
||||||
|
raw = dollars(value)
|
||||||
|
return raw.split(".")[0]
|
||||||
|
|
||||||
|
|
||||||
|
def justCents(value):
|
||||||
|
raw = dollars(value)
|
||||||
|
return raw.split(".")[1]
|
||||||
|
|
||||||
|
|
||||||
def usPhone(number):
|
def usPhone(number):
|
||||||
phone = re.sub(r"\D", "", number)
|
phone = re.sub(r"\D", "", number)
|
||||||
return "+1 ({}) {} - {}".format(phone[0:3], phone[3:6], phone[6:])
|
return "+1 ({}) {} - {}".format(phone[0:3], phone[3:6], phone[6:])
|
||||||
@ -99,6 +109,8 @@ def normalizeOrder(title):
|
|||||||
def register_filters(app):
|
def register_filters(app):
|
||||||
app.jinja_env.filters["iconSvg"] = iconSvg
|
app.jinja_env.filters["iconSvg"] = iconSvg
|
||||||
app.jinja_env.filters["dollars"] = dollars
|
app.jinja_env.filters["dollars"] = dollars
|
||||||
|
app.jinja_env.filters["justDollars"] = justDollars
|
||||||
|
app.jinja_env.filters["justCents"] = justCents
|
||||||
app.jinja_env.filters["usPhone"] = usPhone
|
app.jinja_env.filters["usPhone"] = usPhone
|
||||||
app.jinja_env.filters["readableInteger"] = readableInteger
|
app.jinja_env.filters["readableInteger"] = readableInteger
|
||||||
app.jinja_env.filters["getOptionLabel"] = getOptionLabel
|
app.jinja_env.filters["getOptionLabel"] = getOptionLabel
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
from flask import Blueprint, request as http_request, g, render_template
|
from flask import Blueprint, request as http_request, g, render_template
|
||||||
|
from operator import attrgetter
|
||||||
|
|
||||||
portfolios_bp = Blueprint("portfolios", __name__)
|
portfolios_bp = Blueprint("portfolios", __name__)
|
||||||
|
|
||||||
@ -31,4 +32,24 @@ def portfolio():
|
|||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return {"portfolio": portfolio, "permissions": Permissions, "user_can": user_can}
|
if not portfolio is None:
|
||||||
|
active_task_orders = [
|
||||||
|
task_order for task_order in portfolio.task_orders if task_order.is_active
|
||||||
|
]
|
||||||
|
funding_end_date = (
|
||||||
|
sorted(active_task_orders, key=attrgetter("end_date"))[-1].end_date
|
||||||
|
if active_task_orders
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
funded = len(active_task_orders) > 1
|
||||||
|
else:
|
||||||
|
funding_end_date = None
|
||||||
|
funded = None
|
||||||
|
|
||||||
|
return {
|
||||||
|
"portfolio": portfolio,
|
||||||
|
"permissions": Permissions,
|
||||||
|
"user_can": user_can,
|
||||||
|
"funding_end_date": funding_end_date,
|
||||||
|
"funded": funded,
|
||||||
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from operator import itemgetter
|
|
||||||
|
|
||||||
from flask import g, redirect, render_template, url_for, request as http_request
|
from flask import g, redirect, render_template, url_for, request as http_request
|
||||||
|
|
||||||
@ -41,12 +40,6 @@ def portfolio_funding(portfolio_id):
|
|||||||
task_orders_by_status[task_order.status].append(serialized_task_order)
|
task_orders_by_status[task_order.status].append(serialized_task_order)
|
||||||
|
|
||||||
active_task_orders = task_orders_by_status.get(TaskOrderStatus.ACTIVE, [])
|
active_task_orders = task_orders_by_status.get(TaskOrderStatus.ACTIVE, [])
|
||||||
funding_end_date = (
|
|
||||||
sorted(active_task_orders, key=itemgetter("end_date"))[-1]["end_date"]
|
|
||||||
if active_task_orders
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
funded = len(active_task_orders) > 1
|
|
||||||
total_balance = sum([task_order["balance"] for task_order in active_task_orders])
|
total_balance = sum([task_order["balance"] for task_order in active_task_orders])
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
@ -55,8 +48,6 @@ def portfolio_funding(portfolio_id):
|
|||||||
pending_task_orders=task_orders_by_status.get(TaskOrderStatus.PENDING, []),
|
pending_task_orders=task_orders_by_status.get(TaskOrderStatus.PENDING, []),
|
||||||
active_task_orders=active_task_orders,
|
active_task_orders=active_task_orders,
|
||||||
expired_task_orders=task_orders_by_status.get(TaskOrderStatus.EXPIRED, []),
|
expired_task_orders=task_orders_by_status.get(TaskOrderStatus.EXPIRED, []),
|
||||||
funding_end_date=funding_end_date,
|
|
||||||
funded=funded,
|
|
||||||
total_balance=total_balance,
|
total_balance=total_balance,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -99,6 +99,42 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.column-left {
|
||||||
|
width: 12.5rem;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-right {
|
||||||
|
margin-left: -.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cents {
|
||||||
|
font-size: 2rem;
|
||||||
|
margin-top: .75rem;
|
||||||
|
margin-left: -.7rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portfolio-funding__header--funded-through {
|
||||||
|
flex-grow: 1;
|
||||||
|
text-align: left;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.funded {
|
||||||
|
color: $color-blue;
|
||||||
|
.icon {
|
||||||
|
@include icon-color($color-blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.unfunded {
|
||||||
|
color: $color-red;
|
||||||
|
.icon {
|
||||||
|
@include icon-color($color-red);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin subheading {
|
@mixin subheading {
|
||||||
|
@ -15,14 +15,41 @@
|
|||||||
{{ secondary_breadcrumb or portfolio.name }}
|
{{ secondary_breadcrumb or portfolio.name }}
|
||||||
</div>
|
</div>
|
||||||
<div class='portfolio-header__budget row'>
|
<div class='portfolio-header__budget row'>
|
||||||
<span>Available budget</span>
|
<div class='column-left'>
|
||||||
<button type="button" tabindex="0" class="icon-tooltip" v-tooltip.right="{content: 'The available budget shown includes the available budget of all active task orders', container: false}">
|
<span>Available budget</span>
|
||||||
{{ Icon('info') }}
|
<button type="button" tabindex="0" class="icon-tooltip" v-tooltip.right="{content: 'The available budget shown includes the available budget of all active task orders', container: false}">
|
||||||
</button>
|
{{ Icon('info') }}
|
||||||
<span class='portfolio-header__budget--dollars'>
|
</button>
|
||||||
{{ portfolio.task_orders | selectattr('is_active') | sum(attribute='budget') | dollars }}
|
</div>
|
||||||
</span>
|
<div>
|
||||||
|
<span class='portfolio-header__budget--dollars'>
|
||||||
|
{{ portfolio.task_orders | selectattr('is_active') | sum(attribute='budget') | justDollars }}
|
||||||
|
</span>
|
||||||
|
<span class='cents'>
|
||||||
|
.{{ portfolio.task_orders | selectattr('is_active') | sum(attribute='budget') | justCents }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class='row'>
|
||||||
|
<div class='column-left'></div>
|
||||||
|
<div class='column-right portfolio-funding__header--funded-through {{ "funded" if funding_end_date is not none and funded else "unfunded"}}'>
|
||||||
|
{% if funding_end_date and funded %}
|
||||||
|
{{ Icon('ok') }}
|
||||||
|
Funded through
|
||||||
|
<local-datetime
|
||||||
|
timestamp='{{ funding_end_date }}'
|
||||||
|
format="M/D/YYYY">
|
||||||
|
</local-datetime>
|
||||||
|
{% elif funding_end_date and not funded %}
|
||||||
|
{{ Icon('alert') }}
|
||||||
|
Funded period ends
|
||||||
|
<local-datetime
|
||||||
|
timestamp='{{ funding_end_date }}'
|
||||||
|
format="M/D/YYYY">
|
||||||
|
</local-datetime>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class='row links'>
|
<div class='row links'>
|
||||||
{% if user_can(permissions.VIEW_USAGE_DOLLARS) %}
|
{% if user_can(permissions.VIEW_USAGE_DOLLARS) %}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user