Merge pull request #582 from dod-ccpo/clin-decimals
Accept decimals in CLIN fields
This commit is contained in:
commit
0e8264cbe1
@ -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",
|
||||||
|
@ -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):
|
||||||
|
@ -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(
|
||||||
|
@ -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
|
||||||
},
|
},
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user