Merge pull request #535 from dod-ccpo/update-to-form-per-design-#163066434
Update to form per design - Part 1 of 2
This commit is contained in:
commit
28b10107e7
32
alembic/versions/4536f50b25bc_add_columns_to_task_order.py
Normal file
32
alembic/versions/4536f50b25bc_add_columns_to_task_order.py
Normal file
@ -0,0 +1,32 @@
|
||||
"""add funding columns to task order
|
||||
|
||||
Revision ID: 4536f50b25bc
|
||||
Revises: 3d346b5c8f19
|
||||
Create Date: 2019-01-10 14:24:03.101309
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '4536f50b25bc'
|
||||
down_revision = '3d346b5c8f19'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('task_orders', sa.Column('attachment_id', postgresql.UUID(as_uuid=True), nullable=True))
|
||||
op.add_column('task_orders', sa.Column('performance_length', sa.Integer(), nullable=True))
|
||||
op.create_foreign_key('task_orders_attachments_attachment_id', 'task_orders', 'attachments', ['attachment_id'], ['id'])
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint('task_orders_attachments_attachment_id', 'task_orders', type_='foreignkey')
|
||||
op.drop_column('task_orders', 'performance_length')
|
||||
op.drop_column('task_orders', 'attachment_id')
|
||||
# ### end Alembic commands ###
|
@ -0,0 +1,32 @@
|
||||
"""add oversight columns to task order
|
||||
|
||||
Revision ID: 7f2040715b0d
|
||||
Revises: 4536f50b25bc
|
||||
Create Date: 2019-01-10 16:34:20.185768
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '7f2040715b0d'
|
||||
down_revision = '4536f50b25bc'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('task_orders', sa.Column('cor_phone_number', sa.String(), nullable=True))
|
||||
op.add_column('task_orders', sa.Column('ko_phone_number', sa.String(), nullable=True))
|
||||
op.add_column('task_orders', sa.Column('so_phone_number', sa.String(), nullable=True))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('task_orders', 'so_phone_number')
|
||||
op.drop_column('task_orders', 'ko_phone_number')
|
||||
op.drop_column('task_orders', 'cor_phone_number')
|
||||
# ### end Alembic commands ###
|
@ -24,8 +24,8 @@ class TaskOrders(object):
|
||||
"team_experience",
|
||||
],
|
||||
"funding": [
|
||||
"start_date",
|
||||
"end_date",
|
||||
"performance_length",
|
||||
# "pdf",
|
||||
"clin_01",
|
||||
"clin_02",
|
||||
"clin_03",
|
||||
@ -35,14 +35,17 @@ class TaskOrders(object):
|
||||
"ko_first_name",
|
||||
"ko_last_name",
|
||||
"ko_email",
|
||||
"ko_phone_number",
|
||||
"ko_dod_id",
|
||||
"cor_first_name",
|
||||
"cor_last_name",
|
||||
"cor_email",
|
||||
"cor_phone_number",
|
||||
"cor_dod_id",
|
||||
"so_first_name",
|
||||
"so_last_name",
|
||||
"so_email",
|
||||
"so_phone_number",
|
||||
"so_dod_id",
|
||||
],
|
||||
}
|
||||
|
@ -176,16 +176,20 @@ FUNDING_TYPES = [
|
||||
TASK_ORDER_SOURCES = [("MANUAL", "Manual"), ("EDA", "EDA")]
|
||||
|
||||
APP_MIGRATION = [
|
||||
("on_premise", "Yes, migrating from an on-premise data center"),
|
||||
("cloud", "Yes, migrating from another cloud provider "),
|
||||
("none", "Not planning to migrate any applications "),
|
||||
("on_premise", "Yes, migrating from an <strong>on-premise data center</strong>"),
|
||||
("cloud", "Yes, migrating from <strong>another cloud provider</strong>"),
|
||||
(
|
||||
"both",
|
||||
"Yes, migrating from an <strong>on-premise data center</strong> and <strong>another cloud provider</strong>",
|
||||
),
|
||||
("none", "Not planning to migrate any applications"),
|
||||
("not_sure", "Not Sure"),
|
||||
]
|
||||
|
||||
PROJECT_COMPLEXITY = [
|
||||
("storage", "Storage "),
|
||||
("data_analytics", "Data Analytics "),
|
||||
("conus", "CONUS Only Access "),
|
||||
("conus", "CONUS Access "),
|
||||
("oconus", "OCONUS Access "),
|
||||
("tactical_edge", "Tactical Edge Access "),
|
||||
("not_sure", "Not Sure "),
|
||||
@ -193,11 +197,10 @@ PROJECT_COMPLEXITY = [
|
||||
]
|
||||
|
||||
DEV_TEAM = [
|
||||
("government", "Government"),
|
||||
("civilians", "Civilians"),
|
||||
("government_civilians", "Government Civilians"),
|
||||
("military", "Military "),
|
||||
("contractor", "Contractor "),
|
||||
("other", "Other"),
|
||||
("other", "Other (E.g. University or other partner)"),
|
||||
]
|
||||
|
||||
TEAM_EXPERIENCE = [
|
||||
@ -210,3 +213,30 @@ TEAM_EXPERIENCE = [
|
||||
"Built or migrated many applications, or consulted on several such projects",
|
||||
),
|
||||
]
|
||||
|
||||
PERIOD_OF_PERFORMANCE_LENGTH = [
|
||||
("1", "1 Month"),
|
||||
("2", "2 Months"),
|
||||
("3", "3 Months"),
|
||||
("4", "4 Months"),
|
||||
("5", "5 Months"),
|
||||
("6", "6 Months"),
|
||||
("7", "7 Months"),
|
||||
("8", "8 Months"),
|
||||
("9", "9 Months"),
|
||||
("10", "10 Months"),
|
||||
("11", "11 Months"),
|
||||
("12", "1 Year"),
|
||||
("13", "1 Year, 1 Month"),
|
||||
("14", "1 Year, 2 Months"),
|
||||
("15", "1 Year, 3 Months"),
|
||||
("16", "1 Year, 4 Months"),
|
||||
("17", "1 Year, 5 Months"),
|
||||
("18", "1 Year, 6 Months"),
|
||||
("19", "1 Year, 7 Months"),
|
||||
("20", "1 Year, 8 Months"),
|
||||
("21", "1 Year, 9 Months"),
|
||||
("22", "1 Year, 10 Months"),
|
||||
("23", "1 Year, 11 Months"),
|
||||
("24", "2 Years"),
|
||||
]
|
||||
|
@ -6,12 +6,13 @@ from wtforms.fields import (
|
||||
SelectMultipleField,
|
||||
StringField,
|
||||
TextAreaField,
|
||||
FileField,
|
||||
)
|
||||
from wtforms.fields.html5 import DateField
|
||||
from wtforms.fields.html5 import DateField, TelField
|
||||
from wtforms.widgets import ListWidget, CheckboxInput
|
||||
from wtforms.validators import Required, Length
|
||||
|
||||
from atst.forms.validators import IsNumber
|
||||
from atst.forms.validators import IsNumber, PhoneNumber
|
||||
|
||||
from .forms import CacheableForm
|
||||
from .data import (
|
||||
@ -20,70 +21,84 @@ from .data import (
|
||||
PROJECT_COMPLEXITY,
|
||||
DEV_TEAM,
|
||||
TEAM_EXPERIENCE,
|
||||
PERIOD_OF_PERFORMANCE_LENGTH,
|
||||
)
|
||||
from atst.utils.localization import translate
|
||||
|
||||
|
||||
class AppInfoForm(CacheableForm):
|
||||
portfolio_name = StringField(
|
||||
"Organization Portfolio Name",
|
||||
description="The name of your office or organization. You can add multiple applications to your portfolio. Your task orders are used to pay for these applications and their environments",
|
||||
translate("forms.task_order.portfolio_name_label"),
|
||||
description=translate("forms.task_order.portfolio_name_description"),
|
||||
)
|
||||
scope = TextAreaField(
|
||||
"Cloud Project Scope",
|
||||
description="Your team's plan for using the cloud, such as migrating an existing application or creating a prototype.",
|
||||
translate("forms.task_order.scope_label"),
|
||||
description=translate("forms.task_order.scope_description"),
|
||||
)
|
||||
defense_component = SelectField(
|
||||
"Department of Defense Component", choices=SERVICE_BRANCHES
|
||||
translate("forms.task_order.defense_component_label"), choices=SERVICE_BRANCHES
|
||||
)
|
||||
app_migration = RadioField(
|
||||
"App Migration",
|
||||
description="Do you plan to migrate existing application(s) to the cloud?",
|
||||
translate("forms.task_order.app_migration_label"),
|
||||
description=translate("forms.task_order.app_migration_description"),
|
||||
choices=APP_MIGRATION,
|
||||
default="",
|
||||
)
|
||||
native_apps = RadioField(
|
||||
"Native Apps",
|
||||
description="Do you plan to develop application(s) natively in the cloud? ",
|
||||
translate("forms.task_order.native_apps_label"),
|
||||
description=translate("forms.task_order.native_apps_description"),
|
||||
choices=[("yes", "Yes"), ("no", "No"), ("not_sure", "Not Sure")],
|
||||
)
|
||||
complexity = SelectMultipleField(
|
||||
"Project Complexity",
|
||||
description="Which of these describes how complex your team's use of the cloud will be? (Select all that apply.)",
|
||||
translate("forms.task_order.complexity_label"),
|
||||
description=translate("forms.task_order.complexity_description"),
|
||||
choices=PROJECT_COMPLEXITY,
|
||||
default="",
|
||||
widget=ListWidget(prefix_label=False),
|
||||
option_widget=CheckboxInput(),
|
||||
)
|
||||
complexity_other = StringField("Project Complexity Other")
|
||||
complexity_other = StringField(translate("forms.task_order.complexity_other_label"))
|
||||
dev_team = SelectMultipleField(
|
||||
"Development Team",
|
||||
description="Which people or teams will be completing the development work for your cloud applications?",
|
||||
translate("forms.task_order.dev_team_label"),
|
||||
description=translate("forms.task_order.dev_team_description"),
|
||||
choices=DEV_TEAM,
|
||||
default="",
|
||||
widget=ListWidget(prefix_label=False),
|
||||
option_widget=CheckboxInput(),
|
||||
)
|
||||
dev_team_other = StringField("Development Team Other")
|
||||
dev_team_other = StringField(translate("forms.task_order.dev_team_other_label"))
|
||||
team_experience = RadioField(
|
||||
"Team Experience",
|
||||
description="How much experience does your team have with development in the cloud?",
|
||||
translate("forms.task_order.team_experience_label"),
|
||||
description=translate("forms.task_order.team_experience_description"),
|
||||
choices=TEAM_EXPERIENCE,
|
||||
default="",
|
||||
)
|
||||
|
||||
|
||||
class FundingForm(CacheableForm):
|
||||
start_date = DateField("Start Date", format="%m/%d/%Y")
|
||||
end_date = DateField("End Date", format="%m/%d/%Y")
|
||||
clin_01 = IntegerField("CLIN 01 : Unclassified")
|
||||
clin_02 = IntegerField("CLIN 02: Classified")
|
||||
clin_03 = IntegerField("CLIN 03: Unclassified")
|
||||
clin_04 = IntegerField("CLIN 04: Classified")
|
||||
performance_length = SelectField(
|
||||
translate("forms.task_order.performance_length_label"),
|
||||
choices=PERIOD_OF_PERFORMANCE_LENGTH,
|
||||
)
|
||||
start_date = DateField(
|
||||
translate("forms.task_order.start_date_label"), format="%m/%d/%Y"
|
||||
)
|
||||
end_date = DateField(
|
||||
translate("forms.task_order.end_date_label"), format="%m/%d/%Y"
|
||||
)
|
||||
pdf = FileField(
|
||||
translate("forms.task_order.pdf_label"),
|
||||
description=translate("forms.task_order.pdf_description"),
|
||||
)
|
||||
clin_01 = IntegerField(translate("forms.task_order.clin_01_label"))
|
||||
clin_02 = IntegerField(translate("forms.task_order.clin_02_label"))
|
||||
clin_03 = IntegerField(translate("forms.task_order.clin_03_label"))
|
||||
clin_04 = IntegerField(translate("forms.task_order.clin_04_label"))
|
||||
|
||||
|
||||
class UnclassifiedFundingForm(FundingForm):
|
||||
clin_02 = IntegerField("CLIN 02: Classified (available soon)")
|
||||
clin_04 = IntegerField("CLIN 04: Classified (available soon)")
|
||||
clin_02 = IntegerField(translate("forms.task_order.unclassified_clin_02_label"))
|
||||
clin_04 = IntegerField(translate("forms.task_order.unclassified_clin_04_label"))
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@ -92,52 +107,56 @@ class UnclassifiedFundingForm(FundingForm):
|
||||
|
||||
|
||||
class OversightForm(CacheableForm):
|
||||
ko_first_name = StringField("First Name")
|
||||
ko_last_name = StringField("Last Name")
|
||||
ko_email = StringField("Email")
|
||||
ko_first_name = StringField(
|
||||
translate("forms.task_order.oversight_first_name_label")
|
||||
)
|
||||
ko_last_name = StringField(translate("forms.task_order.oversight_last_name_label"))
|
||||
ko_email = StringField(translate("forms.task_order.oversight_email_label"))
|
||||
ko_phone_number = TelField(
|
||||
translate("forms.task_order.oversight_phone_label"), validators=[PhoneNumber()]
|
||||
)
|
||||
ko_dod_id = StringField(
|
||||
"DOD ID", validators=[Required(), Length(min=10), IsNumber()]
|
||||
translate("forms.task_order.oversight_dod_id_label"),
|
||||
validators=[Required(), Length(min=10), IsNumber()],
|
||||
)
|
||||
|
||||
cor_first_name = StringField("First Name")
|
||||
cor_last_name = StringField("Last Name")
|
||||
cor_email = StringField("Email")
|
||||
cor_first_name = StringField(
|
||||
translate("forms.task_order.oversight_first_name_label")
|
||||
)
|
||||
cor_last_name = StringField(translate("forms.task_order.oversight_last_name_label"))
|
||||
cor_email = StringField(translate("forms.task_order.oversight_email_label"))
|
||||
cor_phone_number = TelField(
|
||||
translate("forms.task_order.oversight_phone_label"), validators=[PhoneNumber()]
|
||||
)
|
||||
cor_dod_id = StringField(
|
||||
"DOD ID", validators=[Required(), Length(min=10), IsNumber()]
|
||||
translate("forms.task_order.oversight_dod_id_label"),
|
||||
validators=[Required(), Length(min=10), IsNumber()],
|
||||
)
|
||||
|
||||
so_first_name = StringField("First Name")
|
||||
so_last_name = StringField("Last Name")
|
||||
so_email = StringField("Email")
|
||||
so_first_name = StringField(
|
||||
translate("forms.task_order.oversight_first_name_label")
|
||||
)
|
||||
so_last_name = StringField(translate("forms.task_order.oversight_last_name_label"))
|
||||
so_email = StringField(translate("forms.task_order.oversight_email_label"))
|
||||
so_phone_number = TelField(
|
||||
translate("forms.task_order.oversight_phone_label"), validators=[PhoneNumber()]
|
||||
)
|
||||
so_dod_id = StringField(
|
||||
"DOD ID", validators=[Required(), Length(min=10), IsNumber()]
|
||||
translate("forms.task_order.oversight_dod_id_label"),
|
||||
validators=[Required(), Length(min=10), IsNumber()],
|
||||
)
|
||||
|
||||
ko_invite = BooleanField(
|
||||
"Invite KO to Task Order Builder",
|
||||
description="""
|
||||
Your KO will need to approve funding for this Task Order by logging
|
||||
into the JEDI Cloud Portal, submitting the Task Order documents
|
||||
within their official system of record, and electronically signing.
|
||||
<i>You may choose to skip this for now and invite them later.</i>
|
||||
""",
|
||||
translate("forms.task_order.ko_invite_label"),
|
||||
description=translate("forms.task_order.skip_invite_description"),
|
||||
)
|
||||
cor_invite = BooleanField(
|
||||
"Invite COR to Task Order Builder",
|
||||
description="""
|
||||
Your COR may assist with submitting the Task Order documents within
|
||||
their official system of record. <i>You may choose to skip this for
|
||||
now and invite them later.</i>
|
||||
""",
|
||||
translate("forms.task_order.cor_invite_label"),
|
||||
description=translate("forms.task_order.skip_invite_description"),
|
||||
)
|
||||
so_invite = BooleanField(
|
||||
"Invite Security Officer to Task Order Builder",
|
||||
description="""
|
||||
Your Security Officer will need to answer some security
|
||||
configuration questions in order to generate a DD-254 document,
|
||||
then electronically sign. <i>You may choose to skip this for now
|
||||
and invite them later.</i>
|
||||
""",
|
||||
translate("forms.task_order.so_invite_label"),
|
||||
description=translate("forms.task_order.skip_invite_description"),
|
||||
)
|
||||
|
||||
|
||||
|
@ -1,6 +1,14 @@
|
||||
from enum import Enum
|
||||
|
||||
from sqlalchemy import Column, Enum as SQLAEnum, Numeric, String, ForeignKey, Date
|
||||
from sqlalchemy import (
|
||||
Column,
|
||||
Enum as SQLAEnum,
|
||||
Numeric,
|
||||
String,
|
||||
ForeignKey,
|
||||
Date,
|
||||
Integer,
|
||||
)
|
||||
from sqlalchemy.types import ARRAY
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
@ -46,6 +54,9 @@ class TaskOrder(Base, mixins.TimestampsMixin):
|
||||
team_experience = Column(String) # Team Experience
|
||||
start_date = Column(Date) # Period of Performance
|
||||
end_date = Column(Date)
|
||||
performance_length = Column(Integer)
|
||||
attachment_id = Column(ForeignKey("attachments.id"))
|
||||
pdf = relationship("Attachment")
|
||||
clin_01 = Column(Numeric(scale=2))
|
||||
clin_02 = Column(Numeric(scale=2))
|
||||
clin_03 = Column(Numeric(scale=2))
|
||||
@ -53,14 +64,17 @@ class TaskOrder(Base, mixins.TimestampsMixin):
|
||||
ko_first_name = Column(String) # First Name
|
||||
ko_last_name = Column(String) # Last Name
|
||||
ko_email = Column(String) # Email
|
||||
ko_phone_number = Column(String) # Phone Number
|
||||
ko_dod_id = Column(String) # DOD ID
|
||||
cor_first_name = Column(String) # First Name
|
||||
cor_last_name = Column(String) # Last Name
|
||||
cor_email = Column(String) # Email
|
||||
cor_phone_number = Column(String) # Phone Number
|
||||
cor_dod_id = Column(String) # DOD ID
|
||||
so_first_name = Column(String) # First Name
|
||||
so_last_name = Column(String) # Last Name
|
||||
so_email = Column(String) # Email
|
||||
so_phone_number = Column(String) # Phone Number
|
||||
so_dod_id = Column(String) # DOD ID
|
||||
number = Column(String, unique=True) # Task Order Number
|
||||
loa = Column(ARRAY(String)) # Line of Accounting (LOA)
|
||||
|
@ -20,7 +20,7 @@ from atst.services.invitation import Invitation as InvitationService
|
||||
TASK_ORDER_SECTIONS = [
|
||||
{
|
||||
"section": "app_info",
|
||||
"title": "What You're Building",
|
||||
"title": "What You're Making",
|
||||
"template": "task_orders/new/app_info.html",
|
||||
"form": task_order_form.AppInfoForm,
|
||||
},
|
||||
@ -166,7 +166,13 @@ class UpdateTaskOrderWorkflow(ShowTaskOrderWorkflow):
|
||||
prefix = officer_type["prefix"]
|
||||
officer_data = {
|
||||
field: getattr(self.task_order, prefix + "_" + field)
|
||||
for field in ["first_name", "last_name", "email", "dod_id"]
|
||||
for field in [
|
||||
"first_name",
|
||||
"last_name",
|
||||
"email",
|
||||
"phone_number",
|
||||
"dod_id",
|
||||
]
|
||||
}
|
||||
officer = TaskOrders.add_officer(
|
||||
self.user, self.task_order, officer_type["role"], officer_data
|
||||
|
@ -3,6 +3,7 @@ import { conformToMask } from 'vue-text-mask'
|
||||
|
||||
import FormMixin from '../../mixins/form'
|
||||
import textinput from '../text_input'
|
||||
import optionsinput from '../options_input'
|
||||
|
||||
export default {
|
||||
name: 'funding',
|
||||
@ -11,6 +12,7 @@ export default {
|
||||
|
||||
components: {
|
||||
textinput,
|
||||
optionsinput
|
||||
},
|
||||
|
||||
props: {
|
||||
|
@ -6,6 +6,7 @@
|
||||
label=field.label | striptags,
|
||||
description=field.description,
|
||||
tooltip='',
|
||||
tooltip_title='Help',
|
||||
placeholder='',
|
||||
validation='anything',
|
||||
paragraph=False,
|
||||
@ -30,7 +31,7 @@
|
||||
<label for={{field.name}}>
|
||||
<div class="usa-input__title">
|
||||
{{ label }}
|
||||
{% if tooltip %}{{ Tooltip(tooltip) }}{% endif %}
|
||||
{% if tooltip %}{{ Tooltip(tooltip, tooltip_title) }}{% endif %}
|
||||
</div>
|
||||
|
||||
{% if field.description %}
|
||||
@ -69,6 +70,7 @@
|
||||
type='text'
|
||||
{% if disabled %}
|
||||
disabled="disabled"
|
||||
readonly="readonly"
|
||||
{% endif %}
|
||||
ref='input'
|
||||
placeholder='{{ placeholder }}'>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{% from "components/text_input.html" import TextInput %}
|
||||
|
||||
{% macro UserInfo(first_name, last_name, email, dod_id) -%}
|
||||
{% macro UserInfo(first_name, last_name, email, phone) -%}
|
||||
<div class='form-row'>
|
||||
<div class='form-col form-col--half'>
|
||||
{{ TextInput(first_name) }}
|
||||
@ -17,7 +17,7 @@
|
||||
</div>
|
||||
|
||||
<div class='form-col form-col--half'>
|
||||
{{ TextInput(dod_id, placeholder='1234567890', validation='dodId') }}
|
||||
{{ TextInput(phone, placeholder='(123) 456-7890', validation='usPhone') }}
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
@ -38,6 +38,7 @@
|
||||
|
||||
<div class='action-group'>
|
||||
<input type='submit' class='usa-button usa-button-primary' value='Save & Continue' />
|
||||
<input class='usa-button usa-button-secondary' value='Save Draft' />
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
@ -6,43 +6,34 @@
|
||||
{% from "components/multi_checkbox_input.html" import MultiCheckboxInput %}
|
||||
|
||||
{% block heading %}
|
||||
What You're Building
|
||||
{{ "task_orders.new.app_info.section_title"| translate }}
|
||||
{% endblock %}
|
||||
|
||||
{% block form %}
|
||||
|
||||
<h3>Basic Information</h3>
|
||||
<!-- App Info Section -->
|
||||
<h3>{{ "task_orders.new.app_info.basic_info_title"| translate }}</h3>
|
||||
{{ TextInput(form.portfolio_name, placeholder="The name of your office or organization") }}
|
||||
{{ TextInput(form.scope, paragraph=True) }}
|
||||
<p>
|
||||
<i>
|
||||
Not sure how to describe your scope? <a href="#">Read some Sample Scopes</a> to
|
||||
get an idea of what is appropriate.
|
||||
</i>
|
||||
</p>
|
||||
<p><i>{{ "task_orders.new.app_info.sample_scope" | translate | safe }}</i></p>
|
||||
{{ OptionsInput(form.defense_component) }}
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>About Your Project</h3>
|
||||
<h3>{{ "task_orders.new.app_info.project_title" | translate }}</h3>
|
||||
{{ OptionsInput(form.app_migration) }}
|
||||
{{ OptionsInput(form.native_apps) }}
|
||||
{{ MultiCheckboxInput(form.complexity, form.complexity_other) }}
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>About Your Team</h3>
|
||||
<h3>{{ "task_orders.new.app_info.team_title" | translate }}</h3>
|
||||
{{ MultiCheckboxInput(form.dev_team, form.dev_team_other) }}
|
||||
{{ OptionsInput(form.team_experience) }}
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>Market Research</h3>
|
||||
<p>
|
||||
The JEDI Cloud Computing Program Office (CCPO) has completed the market
|
||||
research requirement for all related task orders. The Department of Defense CIO
|
||||
has approved this research. <a href="#">View JEDI Cloud Market Research</a>
|
||||
</p>
|
||||
|
||||
<h3>{{ "task_orders.new.app_info.market_research_title" | translate }}</h3>
|
||||
<p>{{ "task_orders.new.app_info.market_research_paragraph" | translate | safe }}</p>
|
||||
|
||||
{% endblock %}
|
||||
|
@ -4,76 +4,51 @@
|
||||
{% from "components/options_input.html" import OptionsInput %}
|
||||
{% from "components/date_input.html" import DateInput %}
|
||||
|
||||
{% from "components/icon.html" import Icon %}
|
||||
|
||||
{% block heading %}
|
||||
Funding
|
||||
{{ "task_orders.new.funding.section_title" | translate }}
|
||||
{% endblock %}
|
||||
|
||||
{% block form %}
|
||||
|
||||
<funding inline-template v-bind:initial-data='{{ form.data|tojson }}'>
|
||||
<div>
|
||||
<div>
|
||||
<!-- Get Funding Section -->
|
||||
<h3>Period of Performance</h3>
|
||||
|
||||
<p>Choose the dates your task order will cover.</p>
|
||||
|
||||
<p>
|
||||
Because your funds will be lost if you don’t use them, we strongly recommend
|
||||
submitting small, short-duration task orders, usually a three month period.
|
||||
We’ll notify you when your period of performance is nearing the end so you can
|
||||
request your next set of funds with a new task order.
|
||||
</p>
|
||||
|
||||
{{ DateInput(form.start_date, placeholder='MM / DD / YYYY', validation='date') }}
|
||||
{{ DateInput(form.end_date, placeholder='MM / DD / YYYY', validation='date') }}
|
||||
<h3>{{ "task_orders.new.funding.performance_period_title" | translate }}</h3>
|
||||
<p>{{ "task_orders.new.funding.performance_period_description" | translate }}</p>
|
||||
<p>{{ "task_orders.new.funding.performance_period_paragraph" | translate }}</p>
|
||||
{{ OptionsInput(form.performance_length) }}
|
||||
|
||||
<hr>
|
||||
<h3>Cloud Usage Estimate</h3>
|
||||
|
||||
<p>
|
||||
Calculate how much your cloud usage will cost. A technical representative
|
||||
should help you complete this calculation.
|
||||
<a href="{{ url_for('atst.jedi_csp_calculator') }}">
|
||||
Cloud Service Provider's estimate calculator
|
||||
</a>
|
||||
</p>
|
||||
<h4>Upload a copy of your CSP Cost Estimate Research</h4>
|
||||
|
||||
<p>
|
||||
Upload your anticipated cloud usage from the CSP tool linked above. PDFs and
|
||||
screengrabs of the tool are sufficient.
|
||||
</p>
|
||||
<p>
|
||||
This is only an estimation tool to help you make and informed evaluation of
|
||||
what you expect to use. While you're tied to the dollar amount you specify in
|
||||
your task order, you're not obligated by the resources you indicate in the
|
||||
calculator.
|
||||
</p>
|
||||
<input type="file">
|
||||
<h3>{{ "task_orders.new.funding.estimate_usage_title" | translate }}</h3>
|
||||
<p>{{ "task_orders.new.funding.estimate_usage_description" | translate }}</p>
|
||||
<p><a class="icon-link" href="{{ url_for('atst.jedi_csp_calculator') }}">
|
||||
{{ Icon("link")}} Cloud Service Provider's estimate calculator
|
||||
</a></p>
|
||||
<p>{{ "task_orders.new.funding.estimate_usage_paragraph" | translate }}</p>
|
||||
<div class="usa-input">
|
||||
{{ form.pdf.label }}
|
||||
{{ form.pdf.description }}
|
||||
<input type="file" disabled="disabled" />
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<h3>Cloud Usage Calculations</h3>
|
||||
<p>
|
||||
Enter the results of your cloud usage calculations. These will correspond with
|
||||
your task order's period of performance.
|
||||
</p>
|
||||
<h4>Cloud Offerings</h4>
|
||||
<p>
|
||||
Infrastructure as a Service (IaaS) and Platform as a Service (PaaS) offerings
|
||||
</p>
|
||||
|
||||
{{ TextInput(form.clin_01, validation='dollars') }}
|
||||
<h3>{{ "task_orders.new.funding.cloud_calculations_title" | translate }}</h3>
|
||||
<p>{{ "task_orders.new.funding.cloud_calculations_paragraph" | translate }}</p>
|
||||
|
||||
<h4>{{ "task_orders.new.funding.cloud_offerings_title" | translate }}</h4>
|
||||
<p>{{ "task_orders.new.funding.cloud_offerings_paragraph" | translate }}</p>
|
||||
{{ TextInput(form.clin_01, validation='dollars', placeholder="$0.00") }}
|
||||
{{ TextInput(form.clin_02, validation='dollars', disabled=(not config.CLASSIFIED)) }}
|
||||
|
||||
<h4>Cloud Support and Assistance</h4>
|
||||
<p>
|
||||
Technical guidance from the cloud service provider, including architecture,
|
||||
configuration of IaaS and PaaS, integration, troubleshooting assistance, and
|
||||
other services.
|
||||
</p>
|
||||
{{ TextInput(form.clin_03, validation='dollars', tooltip='The cloud support and assistance packages cannot be used as a primary development resource.') }}
|
||||
<h4>{{ "task_orders.new.funding.support_assistance_title" | translate }}</h4>
|
||||
<p>{{ "task_orders.new.funding.support_assistance_paragraph" | translate }}</p>
|
||||
{{ TextInput(form.clin_03, validation='dollars', tooltip='The cloud support and assistance packages cannot be used as a primary development resource.', placeholder="$0.00") }}
|
||||
{{ TextInput(form.clin_04, validation='dollars', tooltip='The cloud support and assistance packages cannot be used as a primary development resource.', disabled=(not config.CLASSIFIED)) }}
|
||||
</div>
|
||||
</div>
|
||||
</funding>
|
||||
|
||||
{% endblock %}
|
||||
@ -81,13 +56,10 @@
|
||||
{% block next %}
|
||||
<div class="row">
|
||||
<div class="col col--grow">
|
||||
<p>Total Task Order Value:<br><span id="to-target"></span></p>
|
||||
<p>{{ "task_orders.new.funding.total" | translate }}<br><span id="to-target"></span></p>
|
||||
</div>
|
||||
<div class="col col--grow">
|
||||
{{ super() }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
||||
|
@ -2,24 +2,43 @@
|
||||
|
||||
{% from "components/user_info.html" import UserInfo %}
|
||||
{% from "components/checkbox_input.html" import CheckboxInput %}
|
||||
{% from "components/text_input.html" import TextInput %}
|
||||
|
||||
{% block heading %}
|
||||
Oversight
|
||||
{{ "task_orders.new.oversight.section_title" | translate }}
|
||||
{% endblock %}
|
||||
|
||||
{% block form %}
|
||||
|
||||
<!-- Oversight Section -->
|
||||
<h3>Contracting Officer (KO) Information</h3>
|
||||
{{ UserInfo(form.ko_first_name, form.ko_last_name, form.ko_email, form.ko_dod_id) }}
|
||||
<h3>{{ "task_orders.new.oversight.ko_info_title" | translate }}</h3>
|
||||
<p>{{ "task_orders.new.oversight.ko_info_paragraph" | translate }}</p>
|
||||
{{ UserInfo(form.ko_first_name, form.ko_last_name, form.ko_email, form.ko_phone_number) }}
|
||||
{{ CheckboxInput(form.ko_invite) }}
|
||||
{{ TextInput(form.ko_dod_id, placeholder="1234567890", tooltip="Why", tooltip_title='Why', validation='dodId')}}
|
||||
|
||||
<h3>Contractive Officer Representative (COR) Information</h3>
|
||||
{{ UserInfo(form.cor_first_name, form.cor_last_name, form.cor_email, form.cor_dod_id) }}
|
||||
<hr />
|
||||
|
||||
<h3>{{ "task_orders.new.oversight.cor_info_title" | translate }}</h3>
|
||||
<p>{{ "task_orders.new.oversight.cor_info_paragraph" | translate }}</p>
|
||||
<div class='usa-input'>
|
||||
<fieldset class="usa-input__choices">
|
||||
<legend>
|
||||
<input type="checkbox" name="am_cor" id="am_cor" value="y" />
|
||||
<label for="am_cor">{{ "task_orders.new.oversight.am_cor_label" | translate }}</label>
|
||||
</legend>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{ UserInfo(form.cor_first_name, form.cor_last_name, form.cor_email, form.cor_phone_number) }}
|
||||
{{ CheckboxInput(form.cor_invite) }}
|
||||
{{ TextInput(form.cor_dod_id, placeholder="1234567890", tooltip="Why", tooltip_title='Why', validation='dodId')}}
|
||||
|
||||
<h3>Security Officer Information</h3>
|
||||
{{ UserInfo(form.so_first_name, form.so_last_name, form.so_email, form.so_dod_id) }}
|
||||
<hr />
|
||||
|
||||
<h3>{{ "task_orders.new.oversight.so_info_title" | translate }}</h3>
|
||||
<p>{{ "task_orders.new.oversight.so_info_paragraph" | translate }}</p>
|
||||
{{ UserInfo(form.so_first_name, form.so_last_name, form.so_email, form.so_phone_number) }}
|
||||
{{ CheckboxInput(form.so_invite) }}
|
||||
{{ TextInput(form.so_dod_id, placeholder="1234567890", tooltip="Why", tooltip_title='Why', validation='dodId')}}
|
||||
|
||||
{% endblock %}
|
||||
|
@ -27,7 +27,7 @@
|
||||
<div class="row">
|
||||
<div class="col col--grow">
|
||||
<h3>Period of Performance length {{ TOEditLink(screen=2) }}</h3>
|
||||
{{ task_order.period or RequiredLabel() }}
|
||||
{{ task_order.performance_length or RequiredLabel() }}
|
||||
</div>
|
||||
|
||||
<div class="col col--grow">
|
||||
|
@ -37,6 +37,10 @@ def random_dod_id():
|
||||
return "".join(random.choices(string.digits, k=10))
|
||||
|
||||
|
||||
def random_phone_number():
|
||||
return "".join(random.choices(string.digits, k=10))
|
||||
|
||||
|
||||
def random_future_date(year_min=1, year_max=5):
|
||||
if year_min == year_max:
|
||||
inc = year_min
|
||||
@ -71,9 +75,7 @@ class UserFactory(Base):
|
||||
last_name = factory.Faker("last_name")
|
||||
atat_role = factory.LazyFunction(lambda: Roles.get("default"))
|
||||
dod_id = factory.LazyFunction(random_dod_id)
|
||||
phone_number = factory.LazyFunction(
|
||||
lambda: "".join(random.choices(string.digits, k=10))
|
||||
)
|
||||
phone_number = factory.LazyFunction(random_phone_number)
|
||||
service_branch = factory.LazyFunction(random_service_branch)
|
||||
citizenship = "United States"
|
||||
designation = "military"
|
||||
@ -383,16 +385,20 @@ class TaskOrderFactory(Base):
|
||||
end_date = factory.LazyFunction(
|
||||
lambda *args: random_future_date(year_min=2, year_max=5)
|
||||
)
|
||||
performance_length = random.randint(1, 24)
|
||||
|
||||
ko_first_name = factory.Faker("first_name")
|
||||
ko_last_name = factory.Faker("last_name")
|
||||
ko_email = factory.Faker("email")
|
||||
ko_phone_number = factory.LazyFunction(random_phone_number)
|
||||
ko_dod_id = factory.LazyFunction(random_dod_id)
|
||||
cor_first_name = factory.Faker("first_name")
|
||||
cor_last_name = factory.Faker("last_name")
|
||||
cor_email = factory.Faker("email")
|
||||
cor_phone_number = factory.LazyFunction(random_phone_number)
|
||||
cor_dod_id = factory.LazyFunction(random_dod_id)
|
||||
so_first_name = factory.Faker("first_name")
|
||||
so_last_name = factory.Faker("last_name")
|
||||
so_email = factory.Faker("email")
|
||||
so_phone_number = factory.LazyFunction(random_phone_number)
|
||||
so_dod_id = factory.LazyFunction(random_dod_id)
|
||||
|
@ -224,7 +224,10 @@ def test_task_order_officer_accepts_invite(monkeypatch, client, user_session):
|
||||
"ko_first_name": user_info["first_name"],
|
||||
"ko_last_name": user_info["last_name"],
|
||||
"ko_email": user_info["email"],
|
||||
"ko_phone_number": user_info["phone_number"],
|
||||
"ko_dod_id": user_info["dod_id"],
|
||||
"cor_phone_number": user_info["phone_number"],
|
||||
"so_phone_number": user_info["phone_number"],
|
||||
"so_dod_id": task_order.so_dod_id,
|
||||
"cor_dod_id": task_order.cor_dod_id,
|
||||
"ko_invite": True,
|
||||
|
@ -1,3 +1,13 @@
|
||||
# How to use text containing html tags in .html files:
|
||||
# In the template add the `safe` filter when referencing the string
|
||||
# from the template file. ie:
|
||||
|
||||
# login:
|
||||
# title: A title with <a href="#">a link</a>!
|
||||
|
||||
# `{{ "login.title" | translate | safe }}`
|
||||
|
||||
|
||||
audit_log:
|
||||
events:
|
||||
default:
|
||||
@ -153,6 +163,45 @@ forms:
|
||||
environment_names_required_validation_message: Provide at least one environment name.
|
||||
environment_names_unique_validation_message: Environment names must be unique.
|
||||
name_label: Project Name
|
||||
task_order:
|
||||
portfolio_name_label: Organization Portfolio Name
|
||||
portfolio_name_description: The name of your office or organization. You can add multiple applications to your portfolio. Your task orders are used to pay for these applications and their environments.
|
||||
scope_label: Cloud Project Scope
|
||||
scope_description: Your team's plan for using the cloud, such as migrating an existing application or creating a prototype.
|
||||
defense_component_label: Department of Defense Component
|
||||
app_migration_label: App Migration
|
||||
app_migration_description: Do you plan to migrate existing application(s) to the cloud?
|
||||
native_apps_label: Native Apps
|
||||
native_apps_description: Do you plan to develop application(s) natively in the cloud?
|
||||
complexity_label: Project Complexity
|
||||
complexity_description: Which of these describes how complex your team's use of the cloud will be? Select all that apply.
|
||||
complexity_other_label: Project Complexity Other
|
||||
dev_team_label: Development Team
|
||||
dev_team_description: Which people or teams will be completing the development work for your cloud applications? Select all that apply.
|
||||
dev_team_other_label: Development Team Other
|
||||
team_experience_label: Team Experience
|
||||
team_experience_description: How much experience does your team have with development in the cloud?
|
||||
performance_length_label: Period of Performance length
|
||||
start_date_label: Start Date
|
||||
end_date_label: End Date
|
||||
pdf_label: Upload a copy of your CSP Cost Estimate Research
|
||||
pdf_description: Upload a PDF or screenshot of your usage estimate from the calculator.
|
||||
clin_01_label: 'CLIN 01 : Unclassified'
|
||||
clin_02_label: 'CLIN 02: Classified'
|
||||
clin_03_label: 'CLIN 03: Unclassified'
|
||||
clin_04_label: 'CLIN 04: Classified'
|
||||
unclassified_clin_02_label: 'CLIN 02: Classified (available soon)'
|
||||
unclassified_clin_04_label: 'CLIN 04: Classified (available soon)'
|
||||
oversight_first_name_label: First Name
|
||||
oversight_last_name_label: Last Name
|
||||
oversight_email_label: Email
|
||||
oversight_phone_label: Phone Number
|
||||
oversight_dod_id_label: DoD ID
|
||||
ko_invite_label: Invite KO to Task Order Builder
|
||||
cor_invite_label: Invite COR to Task Order Builder
|
||||
so_invite_label: Invite Security Officer to Task Order Builder
|
||||
skip_invite_description: |
|
||||
<i>You may choose to skip this for now and invite them later.</i>
|
||||
validators:
|
||||
is_number_message: Please enter a valid number.
|
||||
list_item_required_message: Please provide at least one.
|
||||
@ -295,6 +344,42 @@ requests:
|
||||
num_software_systems_tooltip: 'A software system can be any code that you plan to host on cloud infrastructure. For example, it could be a custom-developed web application, or a large ERP system.'
|
||||
questions_title_text: Questions related to JEDI Cloud migration
|
||||
rationalization_software_systems_tooltip: Rationalization is the DoD process to determine whether the application should move to the cloud.
|
||||
task_orders:
|
||||
new:
|
||||
app_info:
|
||||
section_title: "What You're Making"
|
||||
basic_info_title: Basic information
|
||||
sample_scope: |
|
||||
Not sure how to describe your scope? <a href="#">Read some Sample Scopes</a> to get an idea of what is appropriate.
|
||||
project_title: About your project
|
||||
team_title: About your team
|
||||
market_research_title: Market Research
|
||||
market_research_paragraph: 'The JEDI Cloud Computing Program Office (CCPO) has completed the market research requirements for all related task orders. The Department of Defense CIO has approved this research.<br /><a href="#">View JEDI Market Research Memo</a>'
|
||||
funding:
|
||||
section_title: Funding
|
||||
performance_period_title: Period of Performance
|
||||
performance_period_description: Choose the length of time your task order will cover.
|
||||
performance_period_paragraph: Because your funds will be lost if you don’t use them, we strongly recommend submitting small, short-duration task orders, usually a three month period. We’ll notify you when your period of performance is nearing the end so you can request your next set of funds with a new task order.
|
||||
estimate_usage_title: Estimate Your Cloud Usage
|
||||
estimate_usage_description: Calculate how much your cloud usage will cost. A technical representative should help you complete this calculation. These calculations will become your CLINs.
|
||||
estimate_usage_paragraph: This is only an estimation tool to help you make an informed evaluation of what you expect to use. While you're tied to the dollar amount you specify in your task order, you're not obligated by the resources you indicate in the calculator.
|
||||
cloud_calculations_title: Cloud Usage Calculations
|
||||
cloud_calculations_paragraph: Enter the results of your cloud usage calculations.
|
||||
cloud_offerings_title: Cloud Offerings
|
||||
cloud_offerings_paragraph: Infrastructure as a Service (IaaS) and Platform as a Service (PaaS) offerings
|
||||
support_assistance_title: Cloud Support and Assistance
|
||||
support_assistance_paragraph: Technical guidance from the cloud service provider, including architecture, configuration of IaaS and PaaS, integration, troubleshooting assistance, and other services.
|
||||
total: 'Total Task Order Value:'
|
||||
oversight:
|
||||
section_title: Oversight
|
||||
ko_info_title: Contracting Officer (KO) Information
|
||||
ko_info_paragraph: Your KO will need to approve funding for this Task Order by logging into the JEDI Cloud Portal, submitting the Task Order documents within their official system of record, and electronically signing. You might want to work with your program Financial Manager to get your TO documents moving in the right dirction.
|
||||
skip_ko_label: "Skip for now (We'll remind you to enter one later)"
|
||||
cor_info_title: Contractive Officer Representative (COR) Information
|
||||
cor_info_paragraph: Your COR may assist in submitting the Task Order documents within thier official system of record. They may also be invited to log in an manage the Task Order entry within the JEDI Cloud portal.
|
||||
am_cor_label: I am the Contracting Officer Representative (COR) for this Task Order
|
||||
so_info_title: Security Officer Information
|
||||
so_info_paragraph: our Security Officer will need to answer some security configuration questions in order to generate a DD-254 document, then electronically sign.
|
||||
testing:
|
||||
example_string: Hello World
|
||||
example_with_variables: 'Hello, {name}!'
|
||||
|
Loading…
x
Reference in New Issue
Block a user