Merge pull request #682 from dod-ccpo/multiple-loas
Adding Multiple LOA Inputs to KO Review Form
This commit is contained in:
commit
7919dcdac8
30
alembic/versions/db161adbafdf_update_loa_to_array_type.py
Normal file
30
alembic/versions/db161adbafdf_update_loa_to_array_type.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
"""Update LOA to Array Type
|
||||||
|
|
||||||
|
Revision ID: db161adbafdf
|
||||||
|
Revises: 6512aa8d4641
|
||||||
|
Create Date: 2019-02-15 14:28:33.181136
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'db161adbafdf'
|
||||||
|
down_revision = '6512aa8d4641'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.execute("ALTER TABLE task_orders ALTER COLUMN loa TYPE varchar[] USING array[loa]")
|
||||||
|
op.alter_column('task_orders', 'loa', new_column_name='loas')
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.execute("ALTER TABLE task_orders ALTER COLUMN loas TYPE varchar USING loas[1]")
|
||||||
|
op.alter_column('task_orders', 'loas', new_column_name='loa')
|
||||||
|
# ### end Alembic commands ###
|
@ -15,8 +15,6 @@ class ApplicationForm(FlaskForm):
|
|||||||
|
|
||||||
|
|
||||||
class NewApplicationForm(ApplicationForm):
|
class NewApplicationForm(ApplicationForm):
|
||||||
EMPTY_ENVIRONMENT_NAMES = ["", None]
|
|
||||||
|
|
||||||
environment_names = FieldList(
|
environment_names = FieldList(
|
||||||
StringField(label=translate("forms.application.environment_names_label")),
|
StringField(label=translate("forms.application.environment_names_label")),
|
||||||
validators=[
|
validators=[
|
||||||
@ -32,13 +30,3 @@ class NewApplicationForm(ApplicationForm):
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
|
||||||
def data(self):
|
|
||||||
_data = super(FlaskForm, self).data
|
|
||||||
_data["environment_names"] = [
|
|
||||||
n
|
|
||||||
for n in _data["environment_names"]
|
|
||||||
if n not in self.EMPTY_ENVIRONMENT_NAMES
|
|
||||||
]
|
|
||||||
return _data
|
|
||||||
|
@ -5,6 +5,8 @@ from atst.utils.flash import formatted_flash as flash
|
|||||||
|
|
||||||
|
|
||||||
class ValidatedForm(FlaskForm):
|
class ValidatedForm(FlaskForm):
|
||||||
|
EMPTY_LIST_FIELD = ["", None]
|
||||||
|
|
||||||
def perform_extra_validation(self, *args, **kwargs):
|
def perform_extra_validation(self, *args, **kwargs):
|
||||||
"""Performs any applicable extra validation. Must
|
"""Performs any applicable extra validation. Must
|
||||||
return True if the form is valid or False otherwise."""
|
return True if the form is valid or False otherwise."""
|
||||||
@ -13,6 +15,11 @@ class ValidatedForm(FlaskForm):
|
|||||||
@property
|
@property
|
||||||
def data(self):
|
def data(self):
|
||||||
_data = super().data
|
_data = super().data
|
||||||
|
for field in _data:
|
||||||
|
if _data[field].__class__.__name__ == "list":
|
||||||
|
_data[field] = [
|
||||||
|
el for el in _data[field] if el not in self.EMPTY_LIST_FIELD
|
||||||
|
]
|
||||||
_data.pop("csrf_token", None)
|
_data.pop("csrf_token", None)
|
||||||
return _data
|
return _data
|
||||||
|
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
from flask_wtf.file import FileAllowed
|
from flask_wtf.file import FileAllowed
|
||||||
|
|
||||||
from wtforms.fields.html5 import DateField
|
from wtforms.fields.html5 import DateField
|
||||||
from wtforms.fields import StringField, TextAreaField, FileField
|
from wtforms.fields import StringField, TextAreaField, FileField, FieldList
|
||||||
from wtforms.validators import Optional, Length
|
from wtforms.validators import Optional, Length
|
||||||
|
|
||||||
from .forms import CacheableForm
|
from .forms import CacheableForm
|
||||||
from .validators import IsNumber
|
|
||||||
|
|
||||||
from atst.utils.localization import translate
|
from atst.utils.localization import translate
|
||||||
|
|
||||||
@ -26,8 +25,8 @@ class KOReviewForm(CacheableForm):
|
|||||||
number = StringField(
|
number = StringField(
|
||||||
translate("forms.ko_review.to_number"), validators=[Length(min=10)]
|
translate("forms.ko_review.to_number"), validators=[Length(min=10)]
|
||||||
)
|
)
|
||||||
loa = StringField(
|
loas = FieldList(
|
||||||
translate("forms.ko_review.loa"), validators=[Length(min=10), IsNumber()]
|
StringField(translate("forms.ko_review.loa"), validators=[Optional()])
|
||||||
)
|
)
|
||||||
custom_clauses = TextAreaField(
|
custom_clauses = TextAreaField(
|
||||||
translate("forms.ko_review.custom_clauses_label"),
|
translate("forms.ko_review.custom_clauses_label"),
|
||||||
|
@ -90,7 +90,7 @@ class TaskOrder(Base, mixins.TimestampsMixin):
|
|||||||
pdf_attachment_id = Column(ForeignKey("attachments.id"))
|
pdf_attachment_id = Column(ForeignKey("attachments.id"))
|
||||||
_pdf = relationship("Attachment", foreign_keys=[pdf_attachment_id])
|
_pdf = relationship("Attachment", foreign_keys=[pdf_attachment_id])
|
||||||
number = Column(String, unique=True) # Task Order Number
|
number = Column(String, unique=True) # Task Order Number
|
||||||
loa = Column(String) # Line of Accounting (LOA)
|
loas = Column(ARRAY(String)) # Line of Accounting (LOA)
|
||||||
custom_clauses = Column(String) # Custom Clauses
|
custom_clauses = Column(String) # Custom Clauses
|
||||||
signer_dod_id = Column(String)
|
signer_dod_id = Column(String)
|
||||||
signed_at = Column(DateTime)
|
signed_at = Column(DateTime)
|
||||||
|
@ -9,10 +9,18 @@ var paddedNumber = function(number) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Vue.component('date-selector', {
|
export default {
|
||||||
props: ['initialday', 'initialmonth', 'initialyear', 'mindate', 'maxdate'],
|
name: 'date-selector',
|
||||||
|
|
||||||
data() {
|
props: {
|
||||||
|
initialday: { type: String },
|
||||||
|
initialmonth: { type: String },
|
||||||
|
initialyear: { type: String },
|
||||||
|
mindate: { type: String },
|
||||||
|
maxdate: { type: String },
|
||||||
|
},
|
||||||
|
|
||||||
|
data: function() {
|
||||||
return {
|
return {
|
||||||
day: this.initialday,
|
day: this.initialday,
|
||||||
month: this.initialmonth,
|
month: this.initialmonth,
|
||||||
@ -41,7 +49,7 @@ export default Vue.component('date-selector', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
formattedDate() {
|
formattedDate: function() {
|
||||||
let day = paddedNumber(this.day)
|
let day = paddedNumber(this.day)
|
||||||
let month = paddedNumber(this.month)
|
let month = paddedNumber(this.month)
|
||||||
|
|
||||||
@ -52,23 +60,23 @@ export default Vue.component('date-selector', {
|
|||||||
return `${month}/${day}/${this.year}`
|
return `${month}/${day}/${this.year}`
|
||||||
},
|
},
|
||||||
|
|
||||||
isMonthValid() {
|
isMonthValid: function() {
|
||||||
var _month = parseInt(this.month)
|
var _month = parseInt(this.month)
|
||||||
|
|
||||||
return _month >= 0 && _month <= 12
|
return _month >= 0 && _month <= 12
|
||||||
},
|
},
|
||||||
|
|
||||||
isDayValid() {
|
isDayValid: function() {
|
||||||
var _day = parseInt(this.day)
|
var _day = parseInt(this.day)
|
||||||
|
|
||||||
return _day >= 0 && _day <= this.daysMaxCalculation
|
return _day >= 0 && _day <= this.daysMaxCalculation
|
||||||
},
|
},
|
||||||
|
|
||||||
isYearValid() {
|
isYearValid: function() {
|
||||||
return parseInt(this.year) >= 1
|
return parseInt(this.year) >= 1
|
||||||
},
|
},
|
||||||
|
|
||||||
isWithinDateRange() {
|
isWithinDateRange: function() {
|
||||||
let _mindate = this.mindate ? Date.parse(this.mindate) : null
|
let _mindate = this.mindate ? Date.parse(this.mindate) : null
|
||||||
let _maxdate = this.maxdate ? Date.parse(this.maxdate) : null
|
let _maxdate = this.maxdate ? Date.parse(this.maxdate) : null
|
||||||
let _dateTimestamp = Date.UTC(this.year, this.month - 1, this.day)
|
let _dateTimestamp = Date.UTC(this.year, this.month - 1, this.day)
|
||||||
@ -84,7 +92,7 @@ export default Vue.component('date-selector', {
|
|||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
|
|
||||||
isDateValid() {
|
isDateValid: function() {
|
||||||
return (
|
return (
|
||||||
this.day &&
|
this.day &&
|
||||||
this.month &&
|
this.month &&
|
||||||
@ -96,7 +104,7 @@ export default Vue.component('date-selector', {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
daysMaxCalculation() {
|
daysMaxCalculation: function() {
|
||||||
switch (parseInt(this.month)) {
|
switch (parseInt(this.month)) {
|
||||||
case 2: // February
|
case 2: // February
|
||||||
if (this.year) {
|
if (this.year) {
|
||||||
@ -120,7 +128,7 @@ export default Vue.component('date-selector', {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
render(createElement) {
|
render: function(createElement) {
|
||||||
return createElement('p', 'Please implement inline-template')
|
return createElement('p', 'Please implement inline-template')
|
||||||
},
|
},
|
||||||
})
|
}
|
||||||
|
52
js/components/forms/ko_review.js
Normal file
52
js/components/forms/ko_review.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import textinput from '../text_input'
|
||||||
|
import DateSelector from '../date_selector'
|
||||||
|
import uploadinput from '../upload_input'
|
||||||
|
import inputValidations from '../../lib/input_validations'
|
||||||
|
import FormMixin from '../../mixins/form'
|
||||||
|
|
||||||
|
const createLOA = number => ({ number })
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ko-review',
|
||||||
|
|
||||||
|
mixins: [FormMixin],
|
||||||
|
|
||||||
|
components: {
|
||||||
|
textinput,
|
||||||
|
DateSelector,
|
||||||
|
uploadinput,
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
initialData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
modalName: String,
|
||||||
|
},
|
||||||
|
|
||||||
|
data: function() {
|
||||||
|
const loa_list = this.initialData['loas']
|
||||||
|
const loas = (loa_list.length > 0 ? loa_list : ['']).map(createLOA)
|
||||||
|
|
||||||
|
return {
|
||||||
|
loas,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted: function() {
|
||||||
|
this.$root.$on('onLOAAdded', this.addLOA)
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
addLOA: function(event) {
|
||||||
|
this.loas.push(createLOA(''))
|
||||||
|
},
|
||||||
|
|
||||||
|
removeLOA: function(index) {
|
||||||
|
if (this.loas.length > 1) {
|
||||||
|
this.loas.splice(index, 1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
@ -31,6 +31,7 @@ import ConfirmationPopover from './components/confirmation_popover'
|
|||||||
import { isNotInVerticalViewport } from './lib/viewport'
|
import { isNotInVerticalViewport } from './lib/viewport'
|
||||||
import DateSelector from './components/date_selector'
|
import DateSelector from './components/date_selector'
|
||||||
import SidenavToggler from './components/sidenav_toggler'
|
import SidenavToggler from './components/sidenav_toggler'
|
||||||
|
import KoReview from './components/forms/ko_review'
|
||||||
|
|
||||||
Vue.config.productionTip = false
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
@ -64,6 +65,7 @@ const app = new Vue({
|
|||||||
DateSelector,
|
DateSelector,
|
||||||
EditOfficerForm,
|
EditOfficerForm,
|
||||||
SidenavToggler,
|
SidenavToggler,
|
||||||
|
KoReview,
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted: function() {
|
mounted: function() {
|
||||||
|
@ -323,6 +323,53 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.task-order__loa-list {
|
||||||
|
ul {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.task-order__loa-add-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
justify-content: space-between;
|
||||||
|
max-width: 30em;
|
||||||
|
|
||||||
|
.icon-link {
|
||||||
|
&:first-child {
|
||||||
|
margin-right: -$gap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-order__loa-list-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-start;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.usa-input {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loa-list-item__remover {
|
||||||
|
@include icon-link;
|
||||||
|
@include icon-link-vertical;
|
||||||
|
@include icon-link-color($color-red, $color-red-lightest);
|
||||||
|
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-right: -$gap;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
margin-top: 3 * $gap;
|
||||||
|
margin-left: $gap;
|
||||||
|
left: 35em;
|
||||||
|
max-width: 30em;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-order-invitations {
|
.task-order-invitations {
|
||||||
|
@ -11,87 +11,103 @@
|
|||||||
{% from "components/review_field.html" import ReviewField %}
|
{% from "components/review_field.html" import ReviewField %}
|
||||||
{% from "components/upload_input.html" import UploadInput %}
|
{% from "components/upload_input.html" import UploadInput %}
|
||||||
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<ko-review inline-template v-bind:initial-data='{{ form.data|tojson }}'>
|
||||||
|
<div class="col task-order-form">
|
||||||
|
|
||||||
<div class="col task-order-form">
|
{% include "fragments/flash.html" %}
|
||||||
|
|
||||||
{% include "fragments/flash.html" %}
|
{% block form_action %}
|
||||||
|
<form method='POST' action="{{ url_for('portfolios.submit_ko_review', portfolio_id=portfolio.id, task_order_id=task_order.id, form=form) }}" autocomplete="off" enctype="multipart/form-data">
|
||||||
{% block form_action %}
|
|
||||||
<form method='POST' action="{{ url_for('portfolios.submit_ko_review', portfolio_id=portfolio.id, task_order_id=task_order.id, form=form) }}" autocomplete="off" enctype="multipart/form-data">
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{{ form.csrf_token }}
|
|
||||||
|
|
||||||
{% block form %}
|
|
||||||
|
|
||||||
<div class="top-message">
|
|
||||||
<h1 class="subheading title">
|
|
||||||
{{ "task_orders.ko_review.title" | translate }}
|
|
||||||
</h1>
|
|
||||||
{% include "fragments/ko_review_message.html" %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel">
|
|
||||||
|
|
||||||
<div class="panel__heading">
|
|
||||||
<h1 class="task-order-form__heading subheading">
|
|
||||||
<div class="h2">{{ "task_orders.ko_review.review_title" | translate }}</div>
|
|
||||||
{{ "task_orders.new.review.section_title"| translate }}
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel__content">
|
|
||||||
<div class="h2">
|
|
||||||
{{ "task_orders.new.review.app_info"| translate }}
|
|
||||||
</div>
|
|
||||||
{% include "fragments/task_order_review/app_info.html" %}
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<div class="h2">
|
|
||||||
{{ "task_orders.new.review.reporting"| translate }}
|
|
||||||
{{ EditLink(url_for("task_orders.new", screen=1, task_order_id=task_order.id, _anchor="reporting", ko_edit=True)) }}
|
|
||||||
</div>
|
|
||||||
{% include "fragments/task_order_review/reporting.html" %}
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<div class="h2">
|
|
||||||
{{ "task_orders.new.review.funding"| translate }}
|
|
||||||
{{ EditLink(url_for("task_orders.new", screen=2, task_order_id=task_order.id, _anchor="reporting", ko_edit=True)) }}
|
|
||||||
</div>
|
|
||||||
{% include "fragments/task_order_review/funding.html" %}
|
|
||||||
|
|
||||||
<div class="form__sub-fields">
|
|
||||||
{{ DatePicker(form.start_date) }}
|
|
||||||
{{ DatePicker(form.end_date) }}
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<div class="h2">
|
|
||||||
{{ "task_orders.new.review.oversight"| translate }}
|
|
||||||
{{ EditLink(url_for("task_orders.new", screen=3, task_order_id=task_order.id, _anchor="reporting", ko_edit=True)) }}
|
|
||||||
</div>
|
|
||||||
{% include "fragments/task_order_review/oversight.html" %}
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<div class="h2">{{ "task_orders.ko_review.task_order_information"| translate }}</div>
|
|
||||||
|
|
||||||
<div class="form__sub-fields">
|
|
||||||
{{ UploadInput(form.pdf, show_label=True) }}
|
|
||||||
{{ TextInput(form.number, placeholder='1234567890') }}
|
|
||||||
{{ TextInput(form.loa, placeholder='1234567890') }}
|
|
||||||
{{ TextInput(form.custom_clauses, paragraph=True) }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{{ form.csrf_token }}
|
||||||
|
|
||||||
|
{% block form %}
|
||||||
|
|
||||||
|
<div class="top-message">
|
||||||
|
<h1 class="subheading title">
|
||||||
|
{{ "task_orders.ko_review.title" | translate }}
|
||||||
|
</h1>
|
||||||
|
{% include "fragments/ko_review_message.html" %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel__content">
|
||||||
|
|
||||||
|
<div class="h2">
|
||||||
|
{{ "task_orders.new.review.app_info"| translate }}
|
||||||
|
</div>
|
||||||
|
{% include "fragments/task_order_review/app_info.html" %}
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div class="h2">
|
||||||
|
{{ "task_orders.new.review.reporting"| translate }}
|
||||||
|
{{ EditLink(url_for("task_orders.new", screen=1, task_order_id=task_order.id, _anchor="reporting", ko_edit=True)) }}
|
||||||
|
</div>
|
||||||
|
{% include "fragments/task_order_review/reporting.html" %}
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div class="h2">
|
||||||
|
{{ "task_orders.new.review.funding"| translate }}
|
||||||
|
{{ EditLink(url_for("task_orders.new", screen=2, task_order_id=task_order.id, _anchor="reporting", ko_edit=True)) }}
|
||||||
|
</div>
|
||||||
|
{% include "fragments/task_order_review/funding.html" %}
|
||||||
|
|
||||||
|
<div class="form__sub-fields">
|
||||||
|
{{ DatePicker(form.start_date) }}
|
||||||
|
{{ DatePicker(form.end_date) }}
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div class="h2">
|
||||||
|
{{ "task_orders.new.review.oversight"| translate }}
|
||||||
|
{{ EditLink(url_for("task_orders.new", screen=3, task_order_id=task_order.id, _anchor="reporting", ko_edit=True)) }}
|
||||||
|
</div>
|
||||||
|
{% include "fragments/task_order_review/oversight.html" %}
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div class="h2">{{ "task_orders.ko_review.task_order_information"| translate }}</div>
|
||||||
|
|
||||||
|
<div class="form__sub-fields">
|
||||||
|
{{ UploadInput(form.pdf, show_label=True) }}
|
||||||
|
{{ TextInput(form.number, placeholder='1234567890') }}
|
||||||
|
|
||||||
|
<div class="task-order__loa-list">
|
||||||
|
<ul>
|
||||||
|
<li v-for="(loa, i) in loas" class="task-order__loa-list-item">
|
||||||
|
<div class="usa-input usa-input--validation--anything">
|
||||||
|
<label :for="'loas-' + i">
|
||||||
|
<div class="usa-input__title" v-html="'Line of Accounting (LOA) #' + (i + 1)"></div>
|
||||||
|
</label>
|
||||||
|
<input type="text" v-model='loa.number' :id="'loas-' + i" placeholder="1234567890"/>
|
||||||
|
<input type="hidden" :name="'loas-' + i" v-model='loa.number'/>
|
||||||
|
</div>
|
||||||
|
<button v-on:click="removeLOA(i)" v-if="loas.length > 1" type="button" class='loa-list-item__remover'>
|
||||||
|
{{ Icon('trash') }}
|
||||||
|
<span>Remove</span>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="task-order__loa-add-item">
|
||||||
|
<button v-on:click="addLOA" class="icon-link" tabindex="0" type="button">{{ Icon('plus') }} Add another LOA</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ TextInput(form.custom_clauses, paragraph=True) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<div class='action-group'>
|
<div class='action-group'>
|
||||||
<input type='submit' class='usa-button usa-button-primary' value='Continue' />
|
<input type='submit' class='usa-button usa-button-primary' value='Continue' />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
</ko-review>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -358,7 +358,7 @@ def test_submit_completed_ko_review_page_as_cor(client, user_session, pdf_upload
|
|||||||
"start_date": "02/10/2019",
|
"start_date": "02/10/2019",
|
||||||
"end_date": "03/10/2019",
|
"end_date": "03/10/2019",
|
||||||
"number": "1938745981",
|
"number": "1938745981",
|
||||||
"loa": "0813458013405",
|
"loas-0": "0813458013405",
|
||||||
"custom_clauses": "hi im a custom clause",
|
"custom_clauses": "hi im a custom clause",
|
||||||
"pdf": pdf_upload,
|
"pdf": pdf_upload,
|
||||||
}
|
}
|
||||||
@ -397,12 +397,15 @@ def test_submit_completed_ko_review_page_as_ko(client, user_session, pdf_upload)
|
|||||||
|
|
||||||
task_order = TaskOrderFactory.create(portfolio=portfolio, contracting_officer=ko)
|
task_order = TaskOrderFactory.create(portfolio=portfolio, contracting_officer=ko)
|
||||||
user_session(ko)
|
user_session(ko)
|
||||||
|
loa_list = ["123123123", "456456456", "789789789"]
|
||||||
|
|
||||||
form_data = {
|
form_data = {
|
||||||
"start_date": "02/10/2019",
|
"start_date": "02/10/2019",
|
||||||
"end_date": "03/10/2019",
|
"end_date": "03/10/2019",
|
||||||
"number": "1938745981",
|
"number": "1938745981",
|
||||||
"loa": "0813458013405",
|
"loas-0": loa_list[0],
|
||||||
|
"loas-1": loa_list[1],
|
||||||
|
"loas-2": loa_list[2],
|
||||||
"custom_clauses": "hi im a custom clause",
|
"custom_clauses": "hi im a custom clause",
|
||||||
"pdf": pdf_upload,
|
"pdf": pdf_upload,
|
||||||
}
|
}
|
||||||
@ -419,6 +422,7 @@ def test_submit_completed_ko_review_page_as_ko(client, user_session, pdf_upload)
|
|||||||
assert response.headers["Location"] == url_for(
|
assert response.headers["Location"] == url_for(
|
||||||
"task_orders.signature_requested", task_order_id=task_order.id, _external=True
|
"task_orders.signature_requested", task_order_id=task_order.id, _external=True
|
||||||
)
|
)
|
||||||
|
assert task_order.loas == loa_list
|
||||||
|
|
||||||
|
|
||||||
def test_so_review_page(app, client, user_session):
|
def test_so_review_page(app, client, user_session):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user