Merge pull request #582 from dod-ccpo/clin-decimals

Accept decimals in CLIN fields
This commit is contained in:
leigh-mil 2019-01-29 15:54:37 -05:00 committed by GitHub
commit 0e8264cbe1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 59 additions and 23 deletions

View File

@ -1,5 +1,7 @@
from sqlalchemy.orm.exc import NoResultFound from sqlalchemy.orm.exc import NoResultFound
from flask import current_app as app
from atst.database import db from atst.database import db
from atst.models.task_order import TaskOrder from atst.models.task_order import TaskOrder
from atst.models.permissions import Permissions from atst.models.permissions import Permissions
@ -50,6 +52,8 @@ class TaskOrders(object):
], ],
} }
UNCLASSIFIED_FUNDING = ["performance_length", "csp_estimate", "clin_01", "clin_03"]
@classmethod @classmethod
def get(cls, user, task_order_id): def get(cls, user, task_order_id):
try: try:
@ -90,7 +94,7 @@ class TaskOrders(object):
@classmethod @classmethod
def is_section_complete(cls, task_order, section): def is_section_complete(cls, task_order, section):
if section in TaskOrders.SECTIONS: if section in TaskOrders.sections():
for attr in TaskOrders.SECTIONS[section]: for attr in TaskOrders.SECTIONS[section]:
if getattr(task_order, attr) is None: if getattr(task_order, attr) is None:
return False return False
@ -108,6 +112,13 @@ class TaskOrders(object):
return True return True
@classmethod
def sections(cls):
section_list = TaskOrders.SECTIONS
if not app.config.get("CLASSIFIED"):
section_list["funding"] = TaskOrders.UNCLASSIFIED_FUNDING
return section_list
OFFICERS = [ OFFICERS = [
"contracting_officer", "contracting_officer",
"contracting_officer_representative", "contracting_officer_representative",

View File

@ -1,6 +1,6 @@
from wtforms.fields import ( from wtforms.fields import (
BooleanField, BooleanField,
IntegerField, DecimalField,
RadioField, RadioField,
SelectField, SelectField,
SelectMultipleField, SelectMultipleField,
@ -10,7 +10,7 @@ from wtforms.fields import (
) )
from wtforms.fields.html5 import DateField, TelField from wtforms.fields.html5 import DateField, TelField
from wtforms.widgets import ListWidget, CheckboxInput from wtforms.widgets import ListWidget, CheckboxInput
from wtforms.validators import Length from wtforms.validators import Length, InputRequired
from flask_wtf.file import FileAllowed from flask_wtf.file import FileAllowed
from atst.forms.validators import IsNumber, PhoneNumber, RequiredIf from atst.forms.validators import IsNumber, PhoneNumber, RequiredIf
@ -97,20 +97,41 @@ class FundingForm(CacheableForm):
], ],
render_kw={"accept": ".pdf,.png,application/pdf,image/png"}, render_kw={"accept": ".pdf,.png,application/pdf,image/png"},
) )
clin_01 = IntegerField(translate("forms.task_order.clin_01_label")) clin_01 = DecimalField(
clin_02 = IntegerField(translate("forms.task_order.clin_02_label")) translate("forms.task_order.clin_01_label"),
clin_03 = IntegerField(translate("forms.task_order.clin_03_label")) validators=[
clin_04 = IntegerField(translate("forms.task_order.clin_04_label")) InputRequired(message=(translate("forms.task_order.clin_validation_error")))
],
)
clin_02 = DecimalField(
translate("forms.task_order.clin_02_label"),
validators=[
InputRequired(message=(translate("forms.task_order.clin_validation_error")))
],
)
clin_03 = DecimalField(
translate("forms.task_order.clin_03_label"),
validators=[
InputRequired(message=(translate("forms.task_order.clin_validation_error")))
],
)
clin_04 = DecimalField(
translate("forms.task_order.clin_04_label"),
validators=[
InputRequired(message=(translate("forms.task_order.clin_validation_error")))
],
)
class UnclassifiedFundingForm(FundingForm): class UnclassifiedFundingForm(FundingForm):
clin_02 = IntegerField(translate("forms.task_order.unclassified_clin_02_label")) clin_02 = StringField(
clin_04 = IntegerField(translate("forms.task_order.unclassified_clin_04_label")) translate("forms.task_order.unclassified_clin_02_label"),
filters=[lambda x: x or None],
def __init__(self, *args, **kwargs): )
super().__init__(*args, **kwargs) clin_04 = StringField(
self.clin_02.data = "0" translate("forms.task_order.unclassified_clin_04_label"),
self.clin_04.data = "0" filters=[lambda x: x or None],
)
class OversightForm(CacheableForm): class OversightForm(CacheableForm):

View File

@ -128,7 +128,12 @@ class UpdateTaskOrderWorkflow(ShowTaskOrderWorkflow):
self.portfolio_id = portfolio_id self.portfolio_id = portfolio_id
self._task_order = None self._task_order = None
self._section = TASK_ORDER_SECTIONS[screen - 1] self._section = TASK_ORDER_SECTIONS[screen - 1]
self._form = self._section["form"](self.form_data) form_type = (
"unclassified_form"
if "unclassified_form" in self._section and not app.config.get("CLASSIFIED")
else "form"
)
self._form = self._section[form_type](self.form_data)
@property @property
def form(self): def form(self):
@ -277,7 +282,6 @@ def update(screen, task_order_id=None, portfolio_id=None):
workflow = UpdateTaskOrderWorkflow( workflow = UpdateTaskOrderWorkflow(
g.current_user, form_data, screen, task_order_id, portfolio_id g.current_user, form_data, screen, task_order_id, portfolio_id
) )
if workflow.validate(): if workflow.validate():
workflow.update() workflow.update()
return redirect( return redirect(

View File

@ -48,22 +48,21 @@ export default {
totalBudget: function() { totalBudget: function() {
return [this.clin_01, this.clin_02, this.clin_03, this.clin_04].reduce( return [this.clin_01, this.clin_02, this.clin_03, this.clin_04].reduce(
function(acc, curr) { function(acc, curr) {
curr = !curr ? 0 : parseInt(curr) curr = !curr ? 0 : parseFloat(curr)
return acc + curr return acc + curr
}, },
0 0
) )
}, },
totalBudgetStr: function() { totalBudgetStr: function() {
return this.formatDollars(this.totalBudget) return this.totalBudget.toLocaleString('us-US', {
style: 'currency',
currency: 'USD',
})
}, },
}, },
methods: { methods: {
formatDollars: function(intValue) {
const mask = createNumberMask({ prefix: '$', allowDecimal: true })
return conformToMask(intValue.toString(), mask).conformedValue
},
showUploadInput: function() { showUploadInput: function() {
this.showUpload = true this.showUpload = true
}, },

View File

@ -119,7 +119,7 @@ def test_task_order_form_shows_errors(client, user_session):
body = response.data.decode() body = response.data.decode()
assert "There were some errors" in body assert "There were some errors" in body
assert "Not a valid integer" in body assert "Not a valid decimal" in body
@pytest.fixture @pytest.fixture

View File

@ -222,6 +222,7 @@ forms:
clin_02_label: 'CLIN 02: Classified' clin_02_label: 'CLIN 02: Classified'
clin_03_label: 'CLIN 03: Unclassified' clin_03_label: 'CLIN 03: Unclassified'
clin_04_label: 'CLIN 04: Classified' clin_04_label: 'CLIN 04: Classified'
clin_validation_error: Please enter a dollar amount
unclassified_clin_02_label: 'CLIN 02: Classified (available soon)' unclassified_clin_02_label: 'CLIN 02: Classified (available soon)'
unclassified_clin_04_label: 'CLIN 04: Classified (available soon)' unclassified_clin_04_label: 'CLIN 04: Classified (available soon)'
oversight_first_name_label: First Name oversight_first_name_label: First Name