Merge pull request #863 from dod-ccpo/add-clin-to-form

Add CLIN fields to Task Order Form
This commit is contained in:
leigh-mil 2019-06-10 15:11:38 -04:00 committed by GitHub
commit ad385b9de9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 561 additions and 79 deletions

View File

@ -1,6 +1,7 @@
from flask import current_app as app from flask import current_app as app
from atst.database import db from atst.database import db
from atst.models.clin import CLIN
from atst.models.task_order import TaskOrder from atst.models.task_order import TaskOrder
from . import BaseDomainClass from . import BaseDomainClass
@ -18,27 +19,49 @@ class TaskOrders(BaseDomainClass):
UNCLASSIFIED_FUNDING = [] UNCLASSIFIED_FUNDING = []
@classmethod @classmethod
def create(cls, creator, portfolio_id, **kwargs): def create(cls, creator, portfolio_id, number, clins, pdf):
task_order = TaskOrder(portfolio_id=portfolio_id, creator=creator) task_order = TaskOrder(
for key, value in kwargs.items(): portfolio_id=portfolio_id, creator=creator, number=number, pdf=pdf
setattr(task_order, key, value) )
db.session.add(task_order) db.session.add(task_order)
db.session.commit() db.session.commit()
TaskOrders.create_clins(task_order.id, clins)
return task_order return task_order
@classmethod @classmethod
def update(cls, task_order_id, **kwargs): def update(cls, task_order_id, number, clins, pdf):
task_order = TaskOrders.get(task_order_id) task_order = TaskOrders.get(task_order_id)
for key, value in kwargs.items(): task_order.pdf = pdf
setattr(task_order, key, value)
for clin in task_order.clins:
db.session.delete(clin)
if number != task_order.number:
task_order.number = number
db.session.add(task_order)
db.session.add(task_order)
db.session.commit() db.session.commit()
TaskOrders.create_clins(task_order_id, clins)
return task_order return task_order
@classmethod
def create_clins(cls, task_order_id, clin_list):
for clin_data in clin_list:
clin = CLIN(
task_order_id=task_order_id,
number=clin_data["number"],
loas=clin_data["loas"],
start_date=clin_data["start_date"],
end_date=clin_data["end_date"],
obligated_amount=clin_data["obligated_amount"],
jedi_clin_type=clin_data["jedi_clin_type"],
)
db.session.add(clin)
db.session.commit()
@classmethod @classmethod
def section_completion_status(cls, task_order, section): def section_completion_status(cls, task_order, section):
if section in TaskOrders.mission_owner_sections(): if section in TaskOrders.mission_owner_sections():

View File

@ -221,3 +221,10 @@ ENV_ROLE_NO_ACCESS = "No Access"
ENV_ROLES = [(role.value, role.value) for role in CSPRole] + [ ENV_ROLES = [(role.value, role.value) for role in CSPRole] + [
(ENV_ROLE_NO_ACCESS, "No access") (ENV_ROLE_NO_ACCESS, "No access")
] ]
JEDI_CLIN_TYPES = [
("JEDI_CLIN_1", translate("forms.task_order.clin_01_label")),
("JEDI_CLIN_2", translate("forms.task_order.clin_02_label")),
("JEDI_CLIN_3", translate("forms.task_order.clin_03_label")),
("JEDI_CLIN_4", translate("forms.task_order.clin_04_label")),
]

View File

@ -1,13 +1,45 @@
from wtforms.fields import BooleanField, DecimalField, FileField, StringField from wtforms.fields import (
BooleanField,
DecimalField,
FieldList,
FileField,
FormField,
StringField,
)
from wtforms.fields.html5 import DateField from wtforms.fields.html5 import DateField
from wtforms.validators import Required, Optional from wtforms.validators import Required
from flask_wtf.file import FileAllowed from flask_wtf.file import FileAllowed
from flask_wtf import FlaskForm
from .data import JEDI_CLIN_TYPES
from .fields import SelectField
from .forms import BaseForm from .forms import BaseForm
from atst.forms.validators import FileLength from atst.forms.validators import FileLength
from atst.utils.localization import translate from atst.utils.localization import translate
class CLINForm(FlaskForm):
jedi_clin_type = SelectField("Jedi CLIN type", choices=JEDI_CLIN_TYPES)
number = StringField(validators=[Required()])
start_date = DateField(
translate("forms.task_order.start_date_label"),
format="%m/%d/%Y",
validators=[Required()],
)
end_date = DateField(
translate("forms.task_order.end_date_label"),
format="%m/%d/%Y",
validators=[Required()],
)
obligated_amount = DecimalField()
loas = FieldList(StringField())
class UnclassifiedCLINForm(CLINForm):
# TODO: overwrite jedi_clin_type to only include the unclassified options
pass
class TaskOrderForm(BaseForm): class TaskOrderForm(BaseForm):
number = StringField( number = StringField(
translate("forms.task_order.number_label"), translate("forms.task_order.number_label"),
@ -22,38 +54,7 @@ class TaskOrderForm(BaseForm):
], ],
render_kw={"accept": ".pdf,application/pdf"}, render_kw={"accept": ".pdf,application/pdf"},
) )
clins = FieldList(FormField(CLINForm))
class FundingForm(BaseForm):
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"
)
clin_01 = DecimalField(
translate("forms.task_order.clin_01_label"), validators=[Optional()]
)
clin_02 = DecimalField(
translate("forms.task_order.clin_02_label"), validators=[Optional()]
)
clin_03 = DecimalField(
translate("forms.task_order.clin_03_label"), validators=[Optional()]
)
clin_04 = DecimalField(
translate("forms.task_order.clin_04_label"), validators=[Optional()]
)
class UnclassifiedFundingForm(FundingForm):
clin_02 = StringField(
translate("forms.task_order.unclassified_clin_02_label"),
filters=[BaseForm.remove_empty_string],
)
clin_04 = StringField(
translate("forms.task_order.unclassified_clin_04_label"),
filters=[BaseForm.remove_empty_string],
)
class SignatureForm(BaseForm): class SignatureForm(BaseForm):

View File

@ -7,10 +7,10 @@ from atst.models import Base, mixins, types
class JEDICLINType(Enum): class JEDICLINType(Enum):
JEDI_CLIN_1 = "jedi clin 0001" JEDI_CLIN_1 = "JEDI_CLIN_1"
JEDI_CLIN_2 = "jedi clin 0002" JEDI_CLIN_2 = "JEDI_CLIN_2"
JEDI_CLIN_3 = "jedi clin 0003" JEDI_CLIN_3 = "JEDI_CLIN_3"
JEDI_CLIN_4 = "jedi clin 0004" JEDI_CLIN_4 = "JEDI_CLIN_4"
class CLIN(Base, mixins.TimestampsMixin): class CLIN(Base, mixins.TimestampsMixin):
@ -27,3 +27,10 @@ class CLIN(Base, mixins.TimestampsMixin):
end_date = Column(Date, nullable=False) end_date = Column(Date, nullable=False)
obligated_amount = Column(Numeric(scale=2), nullable=False) obligated_amount = Column(Numeric(scale=2), nullable=False)
jedi_clin_type = Column(SQLAEnum(JEDICLINType, native_enum=False), nullable=False) jedi_clin_type = Column(SQLAEnum(JEDICLINType, native_enum=False), nullable=False)
def to_dictionary(self):
return {
c.name: getattr(self, c.name)
for c in self.__table__.columns
if c.name not in ["id"]
}

View File

@ -34,7 +34,7 @@ class TaskOrder(Base, mixins.TimestampsMixin):
signer_dod_id = Column(String) signer_dod_id = Column(String)
signed_at = Column(DateTime) signed_at = Column(DateTime)
clins = relationship("CLIN") clins = relationship("CLIN", back_populates="task_order")
@hybrid_property @hybrid_property
def pdf(self): def pdf(self):
@ -129,6 +129,8 @@ class TaskOrder(Base, mixins.TimestampsMixin):
def to_dictionary(self): def to_dictionary(self):
return { return {
"portfolio_name": self.portfolio_name, "portfolio_name": self.portfolio_name,
"pdf": self.pdf,
"clins": [clin.to_dictionary() for clin in self.clins],
**{ **{
c.name: getattr(self, c.name) c.name: getattr(self, c.name)
for c in self.__table__.columns for c in self.__table__.columns

View File

@ -13,9 +13,7 @@ def render_task_orders_edit(portfolio_id, task_order_id=None, form=None):
if task_order_id: if task_order_id:
task_order = TaskOrders.get(task_order_id) task_order = TaskOrders.get(task_order_id)
render_args["form"] = form or TaskOrderForm( render_args["form"] = form or TaskOrderForm(**task_order.to_dictionary())
number=task_order.number, pdf=task_order.pdf
)
render_args["task_order_id"] = task_order_id render_args["task_order_id"] = task_order_id
else: else:
render_args["form"] = form or TaskOrderForm() render_args["form"] = form or TaskOrderForm()

View File

@ -0,0 +1,19 @@
import DateSelector from './date_selector'
import textinput from './text_input'
export default {
name: 'clin-fields',
components: {
DateSelector,
textinput,
},
props: {
initialClinIndex: Number,
},
data: function() {
return { clinIndex: this.initialClinIndex }
},
}

View File

@ -19,6 +19,7 @@ export default {
initialyear: { type: String }, initialyear: { type: String },
mindate: { type: String }, mindate: { type: String },
maxdate: { type: String }, maxdate: { type: String },
nameTag: { type: String },
}, },
data: function() { data: function() {
@ -26,6 +27,7 @@ export default {
day: this.initialday, day: this.initialday,
month: this.initialmonth, month: this.initialmonth,
year: this.initialyear, year: this.initialyear,
name: this.nameTag,
} }
}, },

View File

@ -0,0 +1,41 @@
import ClinFields from '../clin_fields'
import DateSelector from '../date_selector'
import FormMixin from '../../mixins/form'
import optionsinput from '../options_input'
import textinput from '../text_input'
import uploadinput from '../upload_input'
export default {
name: 'to-form',
mixins: [FormMixin],
components: {
ClinFields,
DateSelector,
optionsinput,
textinput,
uploadinput,
},
props: {
initialClinCount: Number,
},
data: function() {
const clins = this.initialClinCount == 0 ? 1 : 0
const clinIndex = this.initialClinCount == 0 ? 0 : this.initialClinCount - 1
return {
clins,
clinIndex,
}
},
methods: {
addClin: function(event) {
this.clins = this.clins + 1
this.clinIndex = this.clinIndex + 1
},
},
}

View File

@ -41,6 +41,8 @@ import DeleteConfirmation from './components/delete_confirmation'
import NewEnvironment from './components/forms/new_environment' import NewEnvironment from './components/forms/new_environment'
import EnvironmentRole from './components/environment_role' import EnvironmentRole from './components/environment_role'
import SemiCollapsibleText from './components/semi_collapsible_text' import SemiCollapsibleText from './components/semi_collapsible_text'
import ToForm from './components/forms/to_form'
import ClinFields from './components/clin_fields'
Vue.config.productionTip = false Vue.config.productionTip = false
@ -83,6 +85,8 @@ const app = new Vue({
NewEnvironment, NewEnvironment,
EnvironmentRole, EnvironmentRole,
SemiCollapsibleText, SemiCollapsibleText,
ToForm,
ClinFields,
}, },
mounted: function() { mounted: function() {

View File

@ -1,36 +1,256 @@
{% extends "portfolios/base.html" %} {% extends "portfolios/base.html" %}
{% from 'components/date_picker.html' import DatePicker %}
{% from 'components/icon.html' import Icon %}
{% from 'components/save_button.html' import SaveButton %} {% from 'components/save_button.html' import SaveButton %}
{% from 'components/options_input.html' import OptionsInput %}
{% from 'components/text_input.html' import TextInput %} {% from 'components/text_input.html' import TextInput %}
{% from 'components/upload_input.html' import UploadInput %} {% from 'components/upload_input.html' import UploadInput %}
{% macro CLINFields(fields) %}
<div>
<hr>
{{ OptionsInput(fields.jedi_clin_type) }}
{{ TextInput(fields.number) }}
{{ DatePicker(fields.start_date) }}
{{ DatePicker(fields.end_date) }}
{{ TextInput(fields.obligated_amount, validation='dollars') }}
</div>
{% endmacro %}
{% block portfolio_content %} {% block portfolio_content %}
<div class="col task-order-form"> <div class="col task-order-form">
{% include "fragments/flash.html" %} {% include "fragments/flash.html" %}
<base-form inline-template> <to-form inline-template v-bind:initial-clin-count="{{ form.clins.data | length }}">
{% if task_order_id %} {% if task_order_id %}
{% set action = url_for("task_orders.update", portfolio_id=portfolio.id, task_order_id=task_order_id) %} {% set action = url_for("task_orders.update", portfolio_id=portfolio.id, task_order_id=task_order_id) %}
{% else %} {% else %}
{% set action = url_for("task_orders.update", portfolio_id=portfolio.id) %} {% set action = url_for("task_orders.update", portfolio_id=portfolio.id) %}
{% endif %} {% endif %}
<form id="new-task-order" action='{{ action }}' method="POST" autocomplete="off" enctype="multipart/form-data"> <form id="new-task-order" action='{{ action }}' method="POST" autocomplete="off" enctype="multipart/form-data">
{{ form.csrf_token }} {{ form.csrf_token }}
<!-- TODO: implement save bar with component --> <!-- TODO: implement save bar with component -->
<span class="h3">Add Funding</span> <span class="h3">Add Funding</span>
<a <a
href="{{ cancel_url }}" href="{{ cancel_url }}"
class="action-group__action icon-link"> class="action-group__action icon-link">
<span class="icon icon--x"></span> <span class="icon icon--x"></span>
{{ "common.cancel" | translate }} {{ "common.cancel" | translate }}
</a> </a>
{{ SaveButton(text=('common.save' | translate), element='input', form='new-task-order') }} <input type="submit" tabindex="0" value="Save" form="new-task-order" class="usa-button usa-button-primary">
<p> <p>
{{ "task_orders.new.form_help_text" | translate }} {{ "task_orders.new.form_help_text" | translate }}
</p> </p>
<hr> <hr>
{{ TextInput(form.number, validation='taskOrderNumber') }} {{ TextInput(form.number, validation='taskOrderNumber') }}
{% for clin in form.clins %}
{{ CLINFields(clin) }}
{% endfor %}
<div v-for="clin in clins">
<hr>
<clin-fields v-bind:initial-clin-index='clinIndex' inline-template>
<div>
<div class="usa-input">
<fieldset data-ally-disabled="true" class="usa-input__choices">
<legend>
<div class="usa-input__title">
</div>
</legend>
<select :id="'clins-' + clinIndex + '-jedi_clin_type'" :name="'clins-' + clinIndex + '-jedi_clin_type'">
<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>
<textinput :name="'clins-' + clinIndex + '-number'" inline-template>
<div>
<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"> Number </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>
<date-selector :name-tag="'clins-' + clinIndex + '-start_date'" 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'" 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" inline-template>
<div>
<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">Obligated Amount</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'
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>
<button v-on:click="addClin" type="button">
Add CLIN
</button>
{{ UploadInput(form.pdf) }} {{ UploadInput(form.pdf) }}
</form> </form>
</base-form> </to-form>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,4 +1,6 @@
import pytest import pytest
from datetime import date
from decimal import Decimal
from atst.domain.task_orders import TaskOrders, TaskOrderError from atst.domain.task_orders import TaskOrders, TaskOrderError
from atst.domain.exceptions import UnauthorizedError from atst.domain.exceptions import UnauthorizedError
@ -51,3 +53,93 @@ def test_all_sections_complete():
assert not TaskOrders.all_sections_complete(task_order) assert not TaskOrders.all_sections_complete(task_order)
task_order.scope = "str12345" task_order.scope = "str12345"
assert TaskOrders.all_sections_complete(task_order) assert TaskOrders.all_sections_complete(task_order)
def test_create_adds_clins(pdf_upload):
portfolio = PortfolioFactory.create()
clins = [
{
"jedi_clin_type": "JEDI_CLIN_1",
"number": "12312",
"start_date": date(2020, 1, 1),
"end_date": date(2021, 1, 1),
"obligated_amount": Decimal("5000"),
"loas": ["123123123123", "345345234"],
},
{
"jedi_clin_type": "JEDI_CLIN_1",
"number": "12312",
"start_date": date(2020, 1, 1),
"end_date": date(2021, 1, 1),
"obligated_amount": Decimal("5000"),
"loas": ["78979087"],
},
]
task_order = TaskOrders.create(
creator=portfolio.owner,
portfolio_id=portfolio.id,
number="0123456789",
clins=clins,
pdf=pdf_upload,
)
assert len(task_order.clins) == 2
def test_update_adds_clins(pdf_upload):
task_order = TaskOrderFactory.create(number="1231231234")
to_number = task_order.number
clins = [
{
"jedi_clin_type": "JEDI_CLIN_1",
"number": "12312",
"start_date": date(2020, 1, 1),
"end_date": date(2021, 1, 1),
"obligated_amount": Decimal("5000"),
"loas": ["123123123123", "345345234"],
},
{
"jedi_clin_type": "JEDI_CLIN_1",
"number": "12312",
"start_date": date(2020, 1, 1),
"end_date": date(2021, 1, 1),
"obligated_amount": Decimal("5000"),
"loas": ["78979087"],
},
]
task_order = TaskOrders.create(
creator=task_order.creator,
portfolio_id=task_order.portfolio_id,
number="0000000000",
clins=clins,
pdf=pdf_upload,
)
assert task_order.number != to_number
assert len(task_order.clins) == 2
def test_update_does_not_duplicate_clins(pdf_upload):
task_order = TaskOrderFactory.create(number="3453453456", clins=["123", "456"])
clins = [
{
"jedi_clin_type": "JEDI_CLIN_1",
"number": "123",
"start_date": date(2020, 1, 1),
"end_date": date(2021, 1, 1),
"obligated_amount": Decimal("5000"),
"loas": ["123123123123", "345345234"],
},
{
"jedi_clin_type": "JEDI_CLIN_1",
"number": "111",
"start_date": date(2020, 1, 1),
"end_date": date(2021, 1, 1),
"obligated_amount": Decimal("5000"),
"loas": ["78979087"],
},
]
task_order = TaskOrders.update(
task_order_id=task_order.id, number="0000000000", clins=clins, pdf=pdf_upload
)
assert len(task_order.clins) == 2
for clin in task_order.clins:
assert clin.number != "456"

View File

@ -41,6 +41,10 @@ def random_future_date(year_min=1, year_max=5):
return _random_date(year_min, year_max, operator.add) return _random_date(year_min, year_max, operator.add)
def random_loa_numbers():
return ["".join(random.choices(string.digits, k=43))]
def _random_date(year_min, year_max, operation): def _random_date(year_min, year_max, operation):
if year_min == year_max: if year_min == year_max:
inc = year_min inc = year_min
@ -267,6 +271,17 @@ class TaskOrderFactory(Base):
portfolio = factory.SubFactory(PortfolioFactory) portfolio = factory.SubFactory(PortfolioFactory)
number = factory.LazyFunction(random_task_order_number) number = factory.LazyFunction(random_task_order_number)
creator = factory.SubFactory(UserFactory)
@classmethod
def _create(cls, model_class, *args, **kwargs):
with_clins = kwargs.pop("clins", [])
task_order = super()._create(model_class, *args, **kwargs)
for clin in with_clins:
CLINFactory.create(task_order=task_order, number=clin)
return task_order
class CLINFactory(Base): class CLINFactory(Base):

View File

@ -33,24 +33,75 @@ def user():
return UserFactory.create() return UserFactory.create()
def test_task_orders_new(client, user_session, portfolio): def test_task_orders_edit(client, user_session, portfolio):
user_session(portfolio.owner) user_session(portfolio.owner)
response = client.get(url_for("task_orders.edit", portfolio_id=portfolio.id)) response = client.get(url_for("task_orders.edit", portfolio_id=portfolio.id))
assert response.status_code == 200 assert response.status_code == 200
def test_task_orders_create(client, user_session, portfolio, pdf_upload, session): def test_task_orders_update(client, user_session, portfolio):
user_session(portfolio.owner) user_session(portfolio.owner)
data = {"number": "0123456789", "pdf": pdf_upload} form_data = {
"number": "0123456789",
"pdf": pdf_upload,
"clins-0-jedi_clin_type": "JEDI_CLIN_1",
"clins-0-clin_number": "12312",
"clins-0-start_date": "01/01/2020",
"clins-0-end_date": "01/01/2021",
"clins-0-obligated_amount": "5000",
"clins-0-loas-0": "123123123123",
"clins-0-loas-1": "345345234",
"clins-1-jedi_clin_type": "JEDI_CLIN_1",
"clins-1-number": "12312",
"clins-1-start_date": "01/01/2020",
"clins-1-end_date": "01/01/2021",
"clins-1-obligated_amount": "5000",
"clins-1-loas-0": "78979087",
}
response = client.post( response = client.post(
url_for("task_orders.update", portfolio_id=portfolio.id), data=data url_for("task_orders.update", portfolio_id=portfolio.id), data=form_data
) )
assert response.status_code == 302 assert response.status_code == 302
task_order = session.query(TaskOrder).filter_by(number=data["number"]).one() task_order = session.query(TaskOrder).filter_by(number=data["number"]).one()
assert task_order.pdf.filename == pdf_upload.filename assert task_order.pdf.filename == pdf_upload.filename
def test_task_orders_create_invalid_data(client, user_session, portfolio): def test_task_orders_edit_existing_to(client, user_session, task_order):
user_session(task_order.creator)
response = client.get(
url_for(
"task_orders.edit",
portfolio_id=task_order.portfolio_id,
task_order_id=task_order.id,
)
)
assert response.status_code == 200
def test_task_orders_update_existing_to(client, user_session, task_order):
user_session(task_order.creator)
form_data = {
"number": "0123456789",
"clins-0-jedi_clin_type": "JEDI_CLIN_1",
"clins-0-number": "12312",
"clins-0-start_date": "01/01/2020",
"clins-0-end_date": "01/01/2021",
"clins-0-obligated_amount": "5000",
"clins-0-loas-0": "123123123123",
}
response = client.post(
url_for(
"task_orders.update",
portfolio_id=task_order.portfolio_id,
task_order_id=task_order.id,
),
data=form_data,
)
assert response.status_code == 302
assert task_order.number == "0123456789"
def test_task_orders_update_invalid_data(client, user_session, portfolio):
user_session(portfolio.owner) user_session(portfolio.owner)
num_task_orders = len(portfolio.task_orders) num_task_orders = len(portfolio.task_orders)
response = client.post( response = client.post(