diff --git a/atst/forms/task_order.py b/atst/forms/task_order.py index fe764f27..3ac5640b 100644 --- a/atst/forms/task_order.py +++ b/atst/forms/task_order.py @@ -38,6 +38,22 @@ def validate_funding(form, field): ) +def validate_date_in_range(form, field): + contract_start = app.config.get("CONTRACT_START_DATE") + contract_end = app.config.get("CONTRACT_END_DATE") + + if field.data and (field.data < contract_start or field.data > contract_end): + raise ValidationError( + translate( + "forms.task_order.pop_errors.range", + { + "start": contract_start.strftime("%b %d, %Y"), + "end": contract_end.strftime("%b %d, %Y"), + }, + ) + ) + + class CLINForm(FlaskForm): jedi_clin_type = SelectField( translate("task_orders.form.clin_type_label"), @@ -52,13 +68,13 @@ class CLINForm(FlaskForm): translate("task_orders.form.pop_start"), description=translate("task_orders.form.pop_example"), format="%m/%d/%Y", - validators=[Optional()], + validators=[validate_date_in_range], ) end_date = DateField( translate("task_orders.form.pop_end"), description=translate("task_orders.form.pop_example"), format="%m/%d/%Y", - validators=[Optional()], + validators=[validate_date_in_range], ) total_amount = DecimalField( label=translate("task_orders.form.total_funds_label"), @@ -84,8 +100,6 @@ class CLINForm(FlaskForm): def validate(self, *args, **kwargs): valid = super().validate(*args, **kwargs) - contract_start = app.config.get("CONTRACT_START_DATE") - contract_end = app.config.get("CONTRACT_END_DATE") if ( self.start_date.data @@ -97,24 +111,6 @@ class CLINForm(FlaskForm): ) valid = False - if self.start_date.data and self.start_date.data <= contract_start: - self.start_date.errors.append( - translate( - "forms.task_order.pop_errors.start", - {"date": contract_start.strftime("%b %d, %Y")}, - ) - ) - valid = False - - if self.end_date.data and self.end_date.data >= contract_end: - self.end_date.errors.append( - translate( - "forms.task_order.pop_errors.end", - {"date": contract_end.strftime("%b %d, %Y")}, - ) - ) - valid = False - return valid diff --git a/js/components/__tests__/date_selector.test.js b/js/components/__tests__/date_selector.test.js index 348a4726..24d4aed5 100644 --- a/js/components/__tests__/date_selector.test.js +++ b/js/components/__tests__/date_selector.test.js @@ -250,4 +250,33 @@ describe('DateSelector', () => { expect(component.maxError).toEqual(false) }) }) + + describe('outsideRange', () => { + it('should return true if the date is before the minrange', () => { + component.minrange = '2020-01-01' + component.maxrange = '2025-01-01' + component.day = 1 + component.month = 1 + component.year = 2005 + expect(component.outsideRange).toEqual(true) + }) + + it('should return true if the date is after the maxrange', () => { + component.minrange = '2020-01-01' + component.maxrange = '2025-01-01' + component.day = 1 + component.month = 1 + component.year = 2030 + expect(component.outsideRange).toEqual(true) + }) + + it('should return false if the date is betwen minrange and maxrange', () => { + component.minrange = '2020-01-01' + component.maxrange = '2025-01-01' + component.day = 1 + component.month = 1 + component.year = 2022 + expect(component.outsideRange).toEqual(false) + }) + }) }) diff --git a/js/components/date_selector.js b/js/components/date_selector.js index 2717c033..a8257f10 100644 --- a/js/components/date_selector.js +++ b/js/components/date_selector.js @@ -19,6 +19,8 @@ export default { initialyear: { type: String }, mindate: { type: String }, maxdate: { type: String }, + minrange: { type: String }, + maxrange: { type: String }, nameTag: { type: String }, optional: { type: Boolean, @@ -179,6 +181,15 @@ export default { return false }, + outsideRange: function() { + if (!!this.maxrange && !!this.minrange && this.isDateComplete) { + return ( + this.dateParsed < this.minRangeParsed || + this.dateParsed > this.maxRangeParsed + ) + } + }, + maxDateParsed: function() { return new Date(this.maxdate) }, @@ -187,6 +198,14 @@ export default { return new Date(this.mindate) }, + maxRangeParsed: function() { + return new Date(this.maxrange) + }, + + minRangeParsed: function() { + return new Date(this.minrange) + }, + dateParsed: function() { return new Date(this.formattedDate) }, diff --git a/js/test_templates/clin_fields.html b/js/test_templates/clin_fields.html index 57fefe2c..abcd43f3 100644 --- a/js/test_templates/clin_fields.html +++ b/js/test_templates/clin_fields.html @@ -332,6 +332,8 @@ +
+ PoP start date must be before or on September 14, 2022. +
PoP start date must be on or after September 14, 2019.
-
+
PoP start date must be before end date.
@@ -431,6 +436,8 @@ -
+
+ PoP end date must be on or after September 14, 2019. +
+
PoP end date must be after start date.
- PoP end date must be on or after September 14, 2022. + PoP end date must be before or on September 14, 2022.
diff --git a/js/test_templates/pop_date_range.html b/js/test_templates/pop_date_range.html index 2d53ad9b..1eabb4ea 100644 --- a/js/test_templates/pop_date_range.html +++ b/js/test_templates/pop_date_range.html @@ -2,15 +2,15 @@
@@ -19,12 +19,14 @@ @@ -39,10 +41,14 @@ For example: 07 04 1776

+
+ {{ ""}} + PoP start date must be before or on September 14, 2022. +
PoP start date must be on or after September 14, 2019.
-
+
PoP start date must be before end date.
@@ -94,17 +100,17 @@
- + - +
- + - +
@@ -118,12 +124,14 @@ @@ -133,26 +141,26 @@
End Date
- - - + + + @@ -160,11 +168,14 @@ For example: 07 04 1776

-
+
+ PoP end date must be on or after September 14, 2019. +
+
PoP end date must be after start date.
- PoP end date must be on or after September 14, 2022. + PoP end date must be before or on September 14, 2022.
@@ -212,17 +223,17 @@
- + - +
- + - +
diff --git a/js/test_templates/to_form.html b/js/test_templates/to_form.html index a22dc16f..930c4d1d 100644 --- a/js/test_templates/to_form.html +++ b/js/test_templates/to_form.html @@ -203,7 +203,7 @@
- +
@@ -212,10 +212,13 @@

For example: 07 04 1776

+
+ PoP start date must be before or on September 14, 2022. +
PoP start date must be on or after September 14, 2019.
-
+
PoP start date must be before end date.
@@ -251,7 +254,7 @@
- +
@@ -267,11 +270,14 @@

For example: 07 04 1776

-
+
+ PoP end date must be on or after September 14, 2019. +
+
PoP end date must be after start date.
- PoP end date must be on or after September 14, 2022. + PoP end date must be before or on September 14, 2022.
diff --git a/templates/components/pop_date_range.html b/templates/components/pop_date_range.html index 676c7c69..0eea2271 100644 --- a/templates/components/pop_date_range.html +++ b/templates/components/pop_date_range.html @@ -2,6 +2,8 @@ {% from 'components/icon.html' import Icon %} {% macro PopDateRange(start_field=None, end_field=None, mindate=mindate, maxdate=maxdate, optional=True, index=None) %} + {% set formatted_end = maxdate | formattedDate(formatter="%B %d, %Y") %} + {% set formatted_start = mindate | formattedDate(formatter="%B %d, %Y") %} -
- PoP start date must be on or after {{ mindate | formattedDate(formatter="%B %d, %Y") }}. +
+ {{ "forms.task_order.pop_errors.start_past_contract" | translate({"date": formatted_end}) }}
-
- PoP start date must be before end date. +
+ {{ "forms.task_order.pop_errors.start_pre_contract" | translate({"date": formatted_start}) }} +
+
+ {{ "forms.task_order.pop_errors.date_order" | translate }}
@@ -118,6 +125,8 @@ {{ 'task_orders.form.pop_end' | translate }}
- {% set formatted_end_date = maxdate | formattedDate(formatter="%B %d, %Y") %} - {{ Alert(message="task_orders.form.pop_end_alert" | translate({'end_date': formatted_end_date })) }} + {{ Alert(message="task_orders.form.pop_end_alert" | translate({'end_date': formatted_end })) }}

{{ 'task_orders.form.pop_example' | translate }}

-
- PoP end date must be after start date. +
+ {{ "forms.task_order.pop_errors.end_pre_contract" | translate({"date": formatted_start}) }} +
+
+ {{ "forms.task_order.pop_errors.date_order" | translate }}
- PoP end date must be on or after {{ formatted_end_date }}. + {{ "forms.task_order.pop_errors.end_past_contract" | translate({"date": formatted_end}) }}
diff --git a/tests/forms/test_task_order.py b/tests/forms/test_task_order.py index 85a7c6af..de95e555 100644 --- a/tests/forms/test_task_order.py +++ b/tests/forms/test_task_order.py @@ -47,17 +47,24 @@ def test_clin_form_pop_dates_within_contract_dates(): start_date=invalid_start, end_date=invalid_end ) clin_form = CLINForm(obj=invalid_clin) + assert not clin_form.validate() assert ( translate( - "forms.task_order.pop_errors.start", - {"date": CONTRACT_START_DATE.strftime("%b %d, %Y")}, + "forms.task_order.pop_errors.range", + { + "start": CONTRACT_START_DATE.strftime("%b %d, %Y"), + "end": CONTRACT_END_DATE.strftime("%b %d, %Y"), + }, ) ) in clin_form.start_date.errors assert ( translate( - "forms.task_order.pop_errors.end", - {"date": CONTRACT_END_DATE.strftime("%b %d, %Y")}, + "forms.task_order.pop_errors.range", + { + "start": CONTRACT_START_DATE.strftime("%b %d, %Y"), + "end": CONTRACT_END_DATE.strftime("%b %d, %Y"), + }, ) ) in clin_form.end_date.errors diff --git a/translations.yaml b/translations.yaml index 22d3a9ab..80cfd9f9 100644 --- a/translations.yaml +++ b/translations.yaml @@ -211,8 +211,11 @@ forms: number_description: Task order number (13 digits) pop_errors: date_order: PoP start date must be before end date. - end: PoP end date must be before or on {date}. - start: PoP start date must be on or after {date}. + range: Date must be between {start} and {end}. + end_past_contract: PoP end date must be before or on {date}. + end_pre_contract: PoP end date must be after or on {date}. + start_past_contract: PoP start date must be before or on {date}. + start_pre_contract: PoP start date must be on or after {date}. scope_description: 'What do you plan to do on the cloud? Some examples might include migrating an existing application or creating a prototype. You don’t need to include a detailed plan of execution, but should list key requirements. This section will be reviewed by your contracting officer, but won’t be sent to the CCPO.

Not sure how to describe your scope? Read some examples to get some inspiration.

' scope_label: Cloud project scope clin_funding_errors: