- emit CLIN amount and type when amount changes - totals are added correctly based on CLIN type
426 lines
18 KiB
HTML
426 lines
18 KiB
HTML
{% extends "portfolios/base.html" %}
|
|
|
|
{% from 'components/date_picker.html' import DatePicker %}
|
|
{% from 'components/icon.html' import Icon %}
|
|
{% from 'components/options_input.html' import OptionsInput %}
|
|
{% from 'components/save_button.html' import SaveButton %}
|
|
{% from "components/semi_collapsible_text.html" import SemiCollapsibleText %}
|
|
{% from "components/sticky_cta.html" import StickyCTA %}
|
|
{% from 'components/text_input.html' import TextInput %}
|
|
{% from "components/totals_box.html" import TotalsBox %}
|
|
{% from 'components/upload_input.html' import UploadInput %}
|
|
|
|
{% macro LOAInput() %}
|
|
<div v-for="loa in loas">
|
|
<textinput :name="'clins-' + clinIndex + '-loas-' + loaIndex(loa)" :watch='true' inline-template>
|
|
<div class="usa-input usa-input--validation--anything">
|
|
<masked-input
|
|
v-on:input='onInput'
|
|
v-on:blur='onBlur'
|
|
v-on:change='onChange'
|
|
v-bind:value='value'
|
|
v-bind:mask='mask'
|
|
v-bind:pipe='pipe'
|
|
v-bind:keep-char-positions='keepCharPositions'
|
|
v-bind:aria-invalid='showError'
|
|
type='text'
|
|
:id='name'
|
|
ref='input'>
|
|
</masked-input>
|
|
|
|
<input type='hidden' v-bind:value='rawValue' :name='name' />
|
|
|
|
<template v-if='showError'>
|
|
<span class='usa-input__message' v-html='validationError'></span>
|
|
</template>
|
|
<template v-else>
|
|
<span class='usa-input__message'></span>
|
|
</template>
|
|
</div>
|
|
</textinput>
|
|
</div>
|
|
|
|
<!-- TODO: Update icon to match designs -->
|
|
<button
|
|
class="icon-link"
|
|
v-on:click="addLoa"
|
|
type="button">
|
|
{{ Icon('plus') }}
|
|
<span>Add another line of accounting</span>
|
|
</button>
|
|
|
|
{% endmacro %}
|
|
|
|
{% macro CLINFields(fields, index) %}
|
|
{% if index != 0 %}
|
|
<hr>
|
|
{% endif %}
|
|
|
|
<clin-fields
|
|
v-bind:initial-clin-index='{{ index }}'
|
|
v-bind:initial-loa-count="{{ fields.loas.data | length }}"
|
|
v-bind:initial-clin-type="'{{ fields.jedi_clin_type.data }}'"
|
|
v-bind:initial-amount='{{ fields.obligated_amount.data }}'
|
|
inline-template>
|
|
<div>
|
|
<div class="form-row">
|
|
<div class="form-col form-col--two-thirds">
|
|
{{ OptionsInput(fields.jedi_clin_type, watch=True) }}
|
|
</div>
|
|
<div class="form-col form-col--third">
|
|
{{ TextInput(fields.number, watch=True) }}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="usa-input">
|
|
<fieldset class="usa-input__choices task-order__loa-fieldset">
|
|
<legend>
|
|
<div class="usa-input__title">
|
|
Line of accounting (43 characters)
|
|
</div>
|
|
</legend>
|
|
{% for loa in fields.loas %}
|
|
{{ TextInput(loa, showLabel=False, watch=True) }}
|
|
{% endfor %}
|
|
|
|
{{ LOAInput() }}
|
|
</fieldset>
|
|
</div>
|
|
|
|
{{ DatePicker(fields.start_date, watch=True) }}
|
|
{{ DatePicker(fields.end_date, watch=True) }}
|
|
{{ TextInput(fields.obligated_amount, validation='dollars', watch=True) }}
|
|
</div>
|
|
</clin-fields>
|
|
{% endmacro %}
|
|
|
|
{% block portfolio_content %}
|
|
{% if task_order_id %}
|
|
{% set action = url_for("task_orders.update", task_order_id=task_order_id) %}
|
|
{% set review_action = url_for("task_orders.update", task_order_id=task_order_id, review=True) %}
|
|
{% else %}
|
|
{% set action = url_for("task_orders.update", portfolio_id=portfolio.id) %}
|
|
{% set review_action = url_for("task_orders.update", portfolio_id=portfolio.id, review=True) %}
|
|
{% endif %}
|
|
<form id="new-task-order" action='{{ action }}' method="POST" autocomplete="off" enctype="multipart/form-data">
|
|
{{ form.csrf_token }}
|
|
|
|
{% set obligated = task_order.total_obligated_funds if task_order else 0 %}
|
|
{% set total = task_order.total_contract_amount if task_order else 0 %}
|
|
|
|
<to-form
|
|
inline-template
|
|
v-bind:initial-obligated='{{ obligated }}'
|
|
v-bind:initial-total='{{ total }}'
|
|
v-bind:initial-clin-count="{{ form.clins.data | length }}">
|
|
<div>
|
|
{% call StickyCTA(text="Add Funding") %}
|
|
<span class="action-group">
|
|
<!-- todo: implement the review button -->
|
|
<input type="submit" formaction="{{ review_action }}" tabindex="0" value="Review task order" form="new-task-order" class="usa-button usa-button-primary">
|
|
<input
|
|
type="submit"
|
|
class="usa-button usa-button-secondary"
|
|
tabindex="0"
|
|
:disabled="!changed"
|
|
value="{{ 'common.save' | translate }}"
|
|
form="new-task-order"/>
|
|
<a
|
|
href="{{ cancel_url }}"
|
|
class="action-group__action icon-link">
|
|
{{ "common.cancel" | translate }}
|
|
</a>
|
|
</span>
|
|
{% endcall %}
|
|
|
|
<div class="task-order task_order__form">
|
|
<p class="section-description">
|
|
{{ "task_orders.new.form_help_text" | translate }}
|
|
</p>
|
|
|
|
<hr>
|
|
|
|
{% include "fragments/flash.html" %}
|
|
|
|
<div class="row">
|
|
<div class="col">
|
|
<div class="h1">Add your task order</div>
|
|
{{ TextInput(form.number, validation='taskOrderNumber') }}
|
|
|
|
<hr>
|
|
|
|
<div class="h3">Add the summary of cloud funding</div>
|
|
<div>
|
|
Data must match with what is in your uploaded document.
|
|
</div>
|
|
|
|
{% for clin in form.clins %}
|
|
{{ CLINFields(clin, index=loop.index - 1) }}
|
|
{% endfor %}
|
|
|
|
<div v-for="clin in clins">
|
|
<hr v-if="clinIndex !== 0">
|
|
<clin-fields
|
|
v-bind:initial-clin-index='clinIndex'
|
|
v-bind:initial-clin-type="'JEDICLINType.JEDI_CLIN_1'"
|
|
inline-template>
|
|
<div>
|
|
<div class="form-row">
|
|
<div class="form-col form-col--two-thirds">
|
|
<optionsinput :name="'clins-' + clinIndex + '-jedi_clin_type'" :watch='true' inline-template>
|
|
<div class="usa-input">
|
|
<fieldset data-ally-disabled="true" class="usa-input__choices" v-on:change="onInput">
|
|
<legend>
|
|
<div class="usa-input__title">
|
|
CLIN type
|
|
</div>
|
|
</legend>
|
|
<select :id='name' :name='name'>
|
|
<option value="JEDI_CLIN_1">{{ "forms.task_order.clin_01_label" | translate }}</option>
|
|
<option value="JEDI_CLIN_2">{{ "forms.task_order.clin_02_label" | translate }}</option>
|
|
<option value="JEDI_CLIN_3">{{ "forms.task_order.clin_03_label" | translate }}</option>
|
|
<option value="JEDI_CLIN_4">{{ "forms.task_order.clin_04_label" | translate }}</option>
|
|
</select>
|
|
</fieldset>
|
|
</div>
|
|
</optionsinput>
|
|
</div>
|
|
<div class="form-col form-col--third">
|
|
<textinput :name="'clins-' + clinIndex + '-number'" :watch='true' inline-template>
|
|
<div class="usa-input">
|
|
<label :for="name">
|
|
<span v-show='showError'>{{ Icon('alert',classes="icon-validation") }}</span>
|
|
<span v-show='showValid'>{{ Icon('ok',classes="icon-validation") }}</span>
|
|
<div class="usa-input__title">CLIN</div>
|
|
</label>
|
|
|
|
<masked-input
|
|
v-on:input='onInput'
|
|
v-on:blur='onBlur'
|
|
v-on:change='onChange'
|
|
v-bind:value='value'
|
|
v-bind:mask='mask'
|
|
v-bind:pipe='pipe'
|
|
v-bind:keep-char-positions='keepCharPositions'
|
|
v-bind:aria-invalid='showError'
|
|
type='text'
|
|
:id='name'
|
|
ref='input'>
|
|
</masked-input>
|
|
|
|
<input type='hidden' v-bind:value='rawValue' :name='name' />
|
|
|
|
<template v-if='showError'>
|
|
<span class='usa-input__message' v-html='validationError'></span>
|
|
</template>
|
|
<template v-else>
|
|
<span class='usa-input__message'></span>
|
|
</template>
|
|
</div>
|
|
</textinput>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<div class="usa-input">
|
|
<fieldset class="usa-input__choices task-order__loa-fieldset">
|
|
<legend>
|
|
<div class="usa-input__title">
|
|
Line of accounting (43 characters)
|
|
</div>
|
|
</legend>
|
|
{{ LOAInput() }}
|
|
</fieldset>
|
|
</div>
|
|
|
|
<date-selector :name-tag="'clins-' + clinIndex + '-start_date'" :watch='true' inline-template>
|
|
<fieldset class="usa-input date-picker" v-bind:class="{ 'usa-input--success': isDateValid }">
|
|
<legend>
|
|
<div class="usa-input__title">
|
|
Start of period of performance (PoP)
|
|
</div>
|
|
</legend>
|
|
|
|
<div class="date-picker-component">
|
|
<input :name="name" v-bind:value="formattedDate" type="hidden" />
|
|
|
|
<div class="usa-form-group usa-form-group-month">
|
|
<label>Month</label>
|
|
<input
|
|
name="date-month"
|
|
max="12"
|
|
maxlength="2"
|
|
min="1"
|
|
type="number"
|
|
v-bind:class="{ 'usa-input-error': (month && !isMonthValid) }"
|
|
v-model="month"
|
|
/>
|
|
</div>
|
|
|
|
<div class="usa-form-group usa-form-group-day">
|
|
<label>Day</label>
|
|
<input
|
|
name="date-day"
|
|
maxlength="2"
|
|
min="1"
|
|
type="number"
|
|
v-bind:class="{ 'usa-input-error': (day && !isDayValid) }"
|
|
v-bind:max="daysMaxCalculation"
|
|
v-model="day"
|
|
/>
|
|
</div>
|
|
|
|
<div class="usa-form-group usa-form-group-year">
|
|
<label>Year</label>
|
|
<input
|
|
name="date-year"
|
|
maxlength="4"
|
|
type="number"
|
|
v-model="year"
|
|
/>
|
|
|
|
</div>
|
|
|
|
<div class="usa-form-group-date-ok" v-if="isDateValid">
|
|
{{ Icon("ok", classes="icon--green") }}
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</date-selector>
|
|
|
|
<date-selector :name-tag="'clins-' + clinIndex + '-end_date'" :watch='true' inline-template>
|
|
<fieldset class="usa-input date-picker" v-bind:class="{ 'usa-input--success': isDateValid }">
|
|
<legend>
|
|
<div class="usa-input__title">
|
|
End of period of performance (PoP)
|
|
</div>
|
|
</legend>
|
|
|
|
<div class="date-picker-component">
|
|
<input :name="name" v-bind:value="formattedDate" type="hidden" />
|
|
|
|
<div class="usa-form-group usa-form-group-month">
|
|
<label>Month</label>
|
|
<input
|
|
name="date-month"
|
|
max="12"
|
|
maxlength="2"
|
|
min="1"
|
|
type="number"
|
|
v-bind:class="{ 'usa-input-error': (month && !isMonthValid) }"
|
|
v-model="month"
|
|
/>
|
|
</div>
|
|
|
|
<div class="usa-form-group usa-form-group-day">
|
|
<label>Day</label>
|
|
<input
|
|
name="date-day"
|
|
maxlength="2"
|
|
min="1"
|
|
type="number"
|
|
v-bind:class="{ 'usa-input-error': (day && !isDayValid) }"
|
|
v-bind:max="daysMaxCalculation"
|
|
v-model="day"
|
|
/>
|
|
</div>
|
|
|
|
<div class="usa-form-group usa-form-group-year">
|
|
<label>Year</label>
|
|
<input
|
|
name="date-year"
|
|
maxlength="4"
|
|
type="number"
|
|
v-model="year"
|
|
/>
|
|
|
|
</div>
|
|
|
|
<div class="usa-form-group-date-ok" v-if="isDateValid">
|
|
{{ Icon("ok", classes="icon--green") }}
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</date-selector>
|
|
|
|
<textinput :name="'clins-' + clinIndex + '-obligated_amount'" validation="dollars" :watch='true' inline-template>
|
|
<div class="usa-input usa-input--validation--dollars noMaxWidth">
|
|
<label :for="name">
|
|
<div class="usa-input__title">Funds obligated for cloud</div>
|
|
<span v-show='showError'>{{ Icon('alert',classes="icon-validation") }}</span>
|
|
<span v-show='showValid'>{{ Icon('ok',classes="icon-validation") }}</span>
|
|
</label>
|
|
|
|
<masked-input
|
|
v-on:input='onInput'
|
|
v-on:blur='onBlur'
|
|
v-on:change='onChange'
|
|
v-bind:value='value'
|
|
v-bind:mask='mask'
|
|
v-bind:pipe='pipe'
|
|
v-bind:keep-char-positions='keepCharPositions'
|
|
v-bind:aria-invalid='showError'
|
|
v-bind:show-mask='true'
|
|
type='text'
|
|
:id='name'
|
|
ref='input'>
|
|
</masked-input>
|
|
|
|
<input type='hidden' v-bind:value='rawValue' :name='name' />
|
|
|
|
<template v-if='showError'>
|
|
<span class='usa-input__message' v-html='validationError'></span>
|
|
</template>
|
|
<template v-else>
|
|
<span class='usa-input__message'></span>
|
|
</template>
|
|
</div>
|
|
</textinput>
|
|
</div>
|
|
</clin-fields>
|
|
</div>
|
|
|
|
<!-- TODO: Update icon to match designs -->
|
|
<button
|
|
class="icon-link icon-link__add-another-clin"
|
|
v-on:click="addClin"
|
|
type="button">
|
|
{{ Icon('plus') }}
|
|
<span>Add another CLIN or Sub-CLIN</span>
|
|
</button>
|
|
|
|
<hr>
|
|
<div class="h3">Upload your supporting documentation</div>
|
|
<div class="task-order__pdf-help-text">
|
|
Upload a single PDF containing all relevant information. {{ Icon('question')}}
|
|
</div>
|
|
{{ UploadInput(form.pdf, watch=True) }}
|
|
</div>
|
|
|
|
<totals-box
|
|
inline-template
|
|
v-bind:obligated='obligated'
|
|
v-bind:contract-amount='total'
|
|
>
|
|
<div class="col totals-box">
|
|
<div class="h4">Total obligated funds</div>
|
|
<div class="h3" v-html="formattedObligated"></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>
|
|
|
|
<div class="h4">Total contract amount</div>
|
|
<div class="h3" v-html="formattedContractAmount"></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>
|
|
</totals-box>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</to-form>
|
|
</form>
|
|
|
|
{% endblock %}
|