richard-dds ad49d3f71f
Merge pull request #359 from dod-ccpo/task-order-expiration
Fix report display for task order with no expiration date
2018-10-02 10:11:28 -04:00

446 lines
18 KiB
HTML

{% extends "workspaces/base.html" %}
{% from "components/alert.html" import Alert %}
{% from "components/icon.html" import Icon %}
{% from "components/empty_state.html" import EmptyState %}
{% block workspace_content %}
{{ Alert("Budget Report for Workspace " + workspace.name,
message="<p>Track your monthly and cumulative expenditures for your workspace, projects, and environments below.</p>\
<p>Please note that the projected spend is based on the <em>average expense over the last three completed months</em> and therefore does not account for future changes that might be made in scale or configuration of your cloud services.</p>",
actions=[
{"label": "Learn More", "href": url_for('atst.helpdocs'), "icon": "info"}
] ) }}
<div class='funding-summary-row'>
<div class='funding-summary-row__col'>
<div class='panel spend-summary'>
<div class='row'>
<h2 class='spend-summary__heading col'>Workspace Total Spend</h2>
<dl class='spend-summary__budget'>
{% set budget = workspace_totals['budget'] %}
{% set spent = workspace_totals['spent'] %}
{% set remaining = budget - spent %}
<div>
<dt>Budget </dt>
<dd>{{ budget | dollars }}</dd>
</div>
<div>
<dt>Remaining</dt>
<dd>{{ remaining | dollars }}</dd>
</div>
</dl>
</div>
<div>
<meter value='{{ spent }}' min='0' max='{{ budget }}' title='{{ spent | dollars }} Total spend to date'>
<div class='meter__fallback' style='width:{{ (spent / budget) * 100 if budget else 0 }}%;'></div>
</meter>
<dl class='spend-summary__spent'>
<dt>Total spend to date</dt>
<dd>{{ spent | dollars }}</dd>
</dl>
</div>
</div>
</div>
<div class='funding-summary-row__col'>
<div class='panel to-summary'>
<div class='to-summary__row'>
<div class='to-summary__to'>
<h2 class='to-summary__heading'>Task Order</h2>
<dl class='to-summary__to-number'>
<dt class='usa-sr-only'>Task Order Number</dt>
<dd>{{ task_order.number }}</dd>
</dl>
</div>
<div class='to-summary__expiration'>
<dl>
<div>
<dt>Expires</dt>
<dd>
{% if expiration_date %}
<local-datetime
timestamp='{{ expiration_date }}'
format='MMMM D, YYYY'>
</local-datetime>
{% else %}
-
{% endif %}
</dd>
</div>
<div>
<dt>Remaining</dt>
<dd>
{% if remaining_days is not none %}
{{ remaining_days }} days
{% else %}
-
{% endif %}
</dd>
</div>
</dl>
<a href='{{ url_for("workspaces.workspace", workspace_id=workspace.id) }}' class='icon-link'>
Manage Task Order
</a>
</div>
</div>
<dl class='to-summary__co'>
<dt>Contracting Officer</dt>
<dd>
{{ jedi_request.contracting_officer_full_name }}
<a class='icon-link' href='mailto:{{ jedi_request.contracting_officer_email }}'>{{ jedi_request.contracting_officer_email }}</a>
</dd>
</dl>
</div>
</div>
</div>
{% set workspace_totals = monthly_totals['workspace'] %}
{% set current_month_index = current_month.strftime('%m/%Y') %}
{% set prev_month_index = prev_month.strftime('%m/%Y') %}
{% set two_months_ago_index = two_months_ago.strftime('%m/%Y') %}
{% set reports_url = url_for("workspaces.workspace_reports", workspace_id=workspace.id) %}
{% if not workspace.projects %}
{% set can_create_projects = user_can(permissions.ADD_APPLICATION_IN_WORKSPACE) %}
{% set message = 'This workspace has no cloud environments set up, so there is no spending data to report. Create a project with some cloud environments to get started.'
if can_create_projects
else 'This workspace has no cloud environments set up, so there is no spending data to report. Contact the workspace owner to set up some cloud environments.'
%}
{{ EmptyState(
'Nothing to report',
action_label='Add a New Project' if can_create_projects else None,
action_href=url_for('workspaces.new_project', workspace_id=workspace.id) if can_create_projects else None,
icon='chart',
sub_message=message
) }}
{% else %}
<budget-chart
budget={{ budget }}
current-month='{{ current_month_index }}'
expiration-date='{{ expiration_date }}'
v-bind:months='{{ cumulative_budget.months | tojson }}'
inline-template>
<div class='budget-chart panel' ref='panel'>
<header class='budget-chart__header panel__heading panel__heading--tight'>
<h2 class='h3'>Cumulative Budget</h2>
<div class='budget-chart__legend'>
<dl class='budget-chart__legend__spend'>
<div>
<dt>Monthly Spend</dt>
<dd class='budget-chart__legend__dot monthly'><span class='usa-sr-only'>Monthly spend visual key</span></dd>
</div>
<div>
<dt>Accumulated Spend</dt>
<dd class='budget-chart__legend__dot accumulated'><span class='usa-sr-only'>Accumulated spend visual key</span></dd>
</div>
</dl>
<dl class='budget-chart__legend__projected'>
<div>
<dt>Projected</dt>
<dd>
<div class='budget-chart__legend__line spend'><span class='usa-sr-only'>Projected monthly spend visual key</span></div>
<div class='budget-chart__legend__line accumulated'><span class='usa-sr-only'>Projected accumulated spend visual key</span></div>
</dd>
</div>
</dl>
</div>
</header>
<svg v-bind:height='height' v-bind:width='width'>
<defs>
<filter x="-0.04" y="0" width="1.08" height="1" class='filter__text-background' id="text-background">
<feFlood/>
<feComposite in="SourceGraphic"/>
</filter>
</defs>
{# spend/projected budget path lines #}
<path class='budget-chart__projected-path' v-bind:d='projectedPath'></path>
<path class='budget-chart__spend-path' v-bind:d='spendPath'></path>
{# max budget line #}
<line
class='budget-chart__budget-line'
x1='0'
v-bind:x2='width'
v-bind:y1='budgetHeight'
v-bind:y2='budgetHeight'></line>
<g v-for='month in displayedMonths' >
{# make this clickable to focus on that month #}
<a v-bind:href='"{{ reports_url }}?month=" + month.date.monthIndex + "&year=" + month.date.year'>
<defs>
<filter
x="-0.04"
y="0"
width="1.08"
height="1"
class='filter__text-background'
v-bind:class='{ "filter__text-background--highlighted": month.isHighlighted }'
v-bind:id="'text-background__' +month.date.month + month.date.year">
<feFlood/>
<feComposite in="SourceGraphic"/>
</filter>
</defs>
<title>
<span v-html='month.date.month + " " + month.date.year'></span>&nbsp;|&nbsp;<!--
--><template v-if='month.cumulativeTotal'><!--
--><template v-if='month.budget && month.budget.spend'>Spend:</template><!--
--><template v-else>Projected Spend:</template><!--
--><span v-html='month.spendAmount'></span><!--
-->&nbsp;|&nbsp;<!--
--><template v-if='month.budget'>Total:</template><!--
--><template v-else>Projected Total:</template><!--
--><span v-html='month.cumulativeAmount'></span><!--
--></template><!--
--><template v-else>No spend for this month</template>
</title>
{# container block #}
<rect
class='budget-chart__block'
v-bind:class='{ "budget-chart__block--highlighted": month.isHighlighted, "budget-chart__block-is-expiration": month.isExpirationMonth }'
v-bind:width='month.metrics.blockWidth'
v-bind:x='month.metrics.blockX'
v-bind:height='height'></rect>
{# budget bar #}
<rect
v-if='month.budget'
class='budget-chart__bar'
v-bind:class='{ "budget-chart__bar--projected": month.budget.projected }'
v-bind:width='month.metrics.barWidth'
v-bind:height='month.metrics.barHeight'
v-bind:x='month.metrics.barX'
v-bind:y='month.metrics.barY'></rect>
{# projected budget bar #}
<rect
v-if='!month.budget'
class='budget-chart__bar budget-chart__bar--projected'
v-bind:width='month.metrics.barWidth'
v-bind:height='month.metrics.barHeight'
v-bind:x='month.metrics.barX'
v-bind:y='month.metrics.barY'></rect>
{# task order expiration line #}
<line
v-if='month.isExpirationMonth'
class='budget-chart__expiration-line'
v-bind:x1='month.metrics.cumulativeX'
v-bind:x2='month.metrics.cumulativeX'
y1='0'
v-bind:y2='baseHeight'></line>
{# task order expiration label #}
<text
v-bind:filter="'url(#text-background__' + month.date.month + month.date.year + ')'"
v-if='month.isExpirationMonth'
text-anchor='middle'
v-bind:x='month.metrics.cumulativeX'
v-bind:y='budgetHeight + 20'
class='budget-chart__label'>T.O. Expires</text>
{# cumulative dot #}
<circle
v-if='month.cumulativeTotal'
class='budget-chart__cumulative__dot'
v-bind:r='month.metrics.cumulativeR'
v-bind:cx='month.metrics.cumulativeX'
v-bind:cy='month.metrics.cumulativeY'></circle>
{# abbreviated cumulative label #}
<text
v-bind:filter="'url(#text-background__' + month.date.month + month.date.year + ')'"
v-if='month.cumulativeTotal'
v-bind:x='month.metrics.cumulativeX'
v-bind:y='month.metrics.cumulativeY - 10'
text-anchor='middle'
class='budget-chart__label'
v-html='month.abbreviatedCumulative'></text>
{# abbreviated spend label #}
<text
v-bind:filter="'url(#text-background__' + month.date.month + month.date.year + ')'"
v-bind:x='month.metrics.cumulativeX'
v-bind:y='baseHeight + 20'
text-anchor='middle'
class='budget-chart__label'
v-html='"+" + month.abbreviatedSpend'></text>
{# month label #}
<text
v-bind:filter="'url(#text-background__' + month.date.month + month.date.year + ')'"
v-bind:x='month.metrics.cumulativeX'
v-bind:y='baseHeight + 40'
text-anchor='middle'
class='budget-chart__label budget-chart__label--strong'
v-html='month.date.month'></text>
{# year label #}
<text
v-bind:filter="'url(#text-background__' + month.date.month + month.date.year + ')'"
v-if='month.showYear'
v-bind:x='month.metrics.cumulativeX'
v-bind:y='baseHeight + 55'
text-anchor='middle'
class='budget-chart__label budget-chart__label--strong'
v-html='month.date.year'></text>
</g>
</a>
<text
x='20'
v-bind:y='budgetHeight + 20'
class='budget-chart__label'>Total Budget</text>
<text
x='20'
v-bind:y='budgetHeight + 40'
class='budget-chart__label'
v-html='displayBudget'></text>
</svg>
</div>
</budget-chart>
<div class='spend-table responsive-table-wrapper'>
<div class='spend-table__header'>
<h2 class='spend-table__title'>Total spend per month </h2>
<select name='month' id='month' onchange='location = this.value' class='spend-table__month-select'>
{% for m in cumulative_budget["months"] %}
{% set month = m | dateFromString %}
<option
{% if month.month == current_month.month and month.year == current_month.year %}
selected='selected'
{% endif %}
value='{{ url_for("workspaces.workspace_reports",
workspace_id=workspace.id,
month=month.month,
year=month.year) }}'
>
{{ month.strftime('%B %Y') }}
</option>
{% endfor %}
{% if not cumulative_budget["months"] %}
<option>{{ current_month.strftime('%B %Y') }}</option>
{% endif %}
</select>
</div>
<spend-table
v-bind:projects='{{ monthly_totals['projects'] | tojson }}'
v-bind:workspace='{{ workspace_totals | tojson }}'
v-bind:environments='{{ monthly_totals['environments'] | tojson }}'
current-month-index='{{ current_month_index }}'
prev-month-index='{{ prev_month_index }}'
two-months-ago-index='{{ two_months_ago_index }}'
inline-template>
<table>
<thead>
<th scope='col'><span class='usa-sr-only'>Spending scope</span></th>
<th scope='col' class='table-cell--align-right previous-month'>{{ two_months_ago.strftime('%B %Y') }}</th>
<th scope='col' class='table-cell--align-right previous-month'>{{ prev_month.strftime('%B %Y') }}</th>
<th scope='col' class='table-cell--align-right current-month'>{{ current_month.strftime('%B %Y') }}</th>
<th class='current-month'>% of total spend this month</th>
</thead>
<tbody class='spend-table__workspace'>
<tr>
<th scope='row'>Total</th>
<td class='table-cell--align-right previous-month'>{{ workspace_totals.get(two_months_ago_index, 0) | dollars }}</td>
<td class='table-cell--align-right previous-month'>{{ workspace_totals.get(prev_month_index, 0) | dollars }}</td>
<td class='table-cell--align-right current-month'>{{ workspace_totals.get(current_month_index, 0) | dollars }}</td>
<td class='table-cell--expand current-month meter-cell'>
<meter value='{{ workspace_totals.get(current_month_index, 0) }}' min='0' max='{{ workspace_totals.get(current_month_index, 0) }}'>
<div class='meter__fallback' style='width: 100%'></div>
</meter>
</td>
</tr>
</tbody>
<tbody v-for='(project, name) in projectsState' class='spend-table__project'>
<tr>
<th scope='rowgroup'>
<button v-on:click='toggle($event, name)' class='icon-link icon-link--large spend-table__project__toggler'>
<template v-if='project.isVisible'>{{ Icon('caret_down') }}</template>
<template v-else>{{ Icon('caret_right') }}</template>
<span v-html='name'></span>
</button>
</th>
<td class='table-cell--align-right previous-month'>
<span v-html='formatDollars(project[twoMonthsAgoIndex] || 0)'></span>
</td>
<td class='table-cell--align-right previous-month'>
<span v-html='formatDollars(project[prevMonthIndex] || 0)'></span>
</td>
<td class='table-cell--align-right current-month'>
<span v-html='formatDollars(project[currentMonthIndex] || 0)'></span>
</td>
<td class='table-cell--expand current-month meter-cell'>
<span class='spend-table__meter-value'>
<span v-html='round( 100 * ((project[currentMonthIndex] || 0) / (workspace[currentMonthIndex] || 1) )) + "%"'></span>
</span>
<meter v-bind:value='project[currentMonthIndex] || 0' min='0' v-bind:max='workspace[currentMonthIndex] || 1'>
<div class='meter__fallback' v-bind:style='"width:" + round( 100 * ((project[currentMonthIndex] || 0) / (workspace[currentMonthIndex] || 1) )) + "%;"'></div>
</meter>
</td>
</tr>
<tr v-for='(environment, envName) in environments[name]' v-show='project.isVisible' class='spend-table__project__env'>
<th scope='rowgroup'>
<a href='#' class='icon-link spend-table__project__env'>
{{ Icon('link') }}
<span v-html='envName'></span>
</a>
</th>
<td class='table-cell--align-right previous-month'>
<span v-html='formatDollars(environment[twoMonthsAgoIndex] || 0)'></span>
</td>
<td class='table-cell--align-right previous-month'>
<span v-html='formatDollars(environment[prevMonthIndex] || 0)'></span>
</td>
<td class='table-cell--align-right current-month'>
<span v-html='formatDollars(environment[currentMonthIndex] || 0)'></span>
</td>
<td class='table-cell--expand current-month'></td>
</tr>
</tbody>
</table>
</spend-table>
</div>
{% endif %}
{% endblock %}