Skip to content

Commit

Permalink
ICMSLST-1349 - SupplementaryReportForm Restrict year range for Date R…
Browse files Browse the repository at this point in the history
…eceived to 6 years
  • Loading branch information
chris-pettinga committed Feb 28, 2024
1 parent e719f75 commit d3b181b
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 13 deletions.
2 changes: 2 additions & 0 deletions pii-ner-exclude.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3857,3 +3857,5 @@ Create Reports Data
the Supplementary Report
{{ application_field(report.transport |
Add New Supplementary Report
jQuery
"Check if the date
6 changes: 4 additions & 2 deletions web/domains/case/_import/fa_dfl/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from web.domains.case._import.forms import ChecklistBaseForm
from web.domains.case.forms import application_contacts
from web.domains.file.utils import ICMSFileField
from web.forms.fields import JqueryDateField
from web.forms.fields import PastOnlyJqueryDateField
from web.forms.mixins import OptionalFormMixin
from web.models import Country

Expand Down Expand Up @@ -178,7 +178,9 @@ def clean(self) -> dict[str, Any]:


class DFLSupplementaryReportForm(forms.ModelForm):
date_received = JqueryDateField(required=True, label="Date Received")
date_received = PastOnlyJqueryDateField(
required=True, label="Date Received", year_select_range=6
)

class Meta:
model = models.DFLSupplementaryReport
Expand Down
6 changes: 4 additions & 2 deletions web/domains/case/_import/fa_oil/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from web.domains.case._import.forms import ChecklistBaseForm
from web.domains.case.forms import application_contacts
from web.domains.file.utils import ICMSFileField
from web.forms.fields import JqueryDateField
from web.forms.fields import PastOnlyJqueryDateField
from web.forms.mixins import OptionalFormMixin
from web.models import Country

Expand Down Expand Up @@ -123,7 +123,9 @@ def clean(self) -> dict[str, Any]:


class OILSupplementaryReportForm(forms.ModelForm):
date_received = JqueryDateField(required=True, label="Date Received")
date_received = PastOnlyJqueryDateField(
required=True, label="Date Received", year_select_range=6
)

class Meta:
model = models.OILSupplementaryReport
Expand Down
6 changes: 4 additions & 2 deletions web/domains/case/_import/fa_sil/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from web.domains.case._import.forms import ChecklistBaseForm
from web.domains.case.forms import application_contacts
from web.forms.fields import JqueryDateField
from web.forms.fields import PastOnlyJqueryDateField
from web.forms.mixins import OptionalFormMixin
from web.forms.widgets import YesNoRadioSelectInline
from web.models import Country, ObsoleteCalibre, Template
Expand Down Expand Up @@ -574,7 +574,9 @@ def clean(self) -> dict[str, Any]:


class SILSupplementaryReportForm(forms.ModelForm):
date_received = JqueryDateField(required=True, label="Date Received")
date_received = PastOnlyJqueryDateField(
required=True, label="Date Received", year_select_range=6
)

class Meta:
model = models.SILSupplementaryReport
Expand Down
52 changes: 52 additions & 0 deletions web/forms/fields.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import datetime as dt
import re
from typing import Any

import phonenumber_field.formfields
from django import forms
from django.forms import Widget
from phonenumber_field.widgets import PhoneNumberInternationalFallbackWidget

from .utils import clean_postcode
Expand Down Expand Up @@ -69,3 +71,53 @@ def to_python(self, value: str) -> str:
class JqueryDateField(forms.DateField):
widget = DateInput(format=JQUERY_DATE_FORMAT)
input_formats = [JQUERY_DATE_FORMAT]

def __init__(self, *args, year_select_range: int = 100, **kwargs) -> None:
self.year_select_range = year_select_range
super().__init__(*args, **kwargs)

def widget_attrs(self, widget: Widget) -> dict[str, Any]:
attrs = super().widget_attrs(widget)
# we want to pass this attribute to the widget so jQuery can use it
attrs["data-year-select-range"] = self.year_select_range
return attrs

def validate(self, value: dt.datetime) -> None:
"""Check if the date is within the year_select_range (if it has been provided)."""
if self.year_select_range and value:
current_year = dt.date.today().year
if abs(value.year - current_year) > self.year_select_range:
raise forms.ValidationError(
f"Date cannot be more than {self.year_select_range} years in the past/future."
)
return super().validate(value)


class PastOnlyJqueryDateField(JqueryDateField):
"""A jQuery datepicker field that only allows past dates."""

def widget_attrs(self, widget: Widget) -> dict[str, Any]:
attrs = super().widget_attrs(widget)
attrs["data-past-only"] = "yes"
return attrs

def validate(self, value: dt.datetime) -> None:
current_year = dt.date.today().year
if value.year > current_year:
raise forms.ValidationError("Date cannot be in the future.")
return super().validate(value)


class FutureOnlyJqueryDateField(JqueryDateField):
"""A jQuery datepicker field that only allows future dates."""

def widget_attrs(self, widget: Widget) -> dict[str, Any]:
attrs = super().widget_attrs(widget)
attrs["data-future-only"] = "yes"
return attrs

def validate(self, value: dt.datetime) -> None:
current_year = dt.date.today().year
if value.year < current_year:
raise forms.ValidationError("Date cannot be in the past.")
return super().validate(value)
34 changes: 27 additions & 7 deletions web/static/web/js/fox/core-footer.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

70 changes: 70 additions & 0 deletions web/tests/domains/case/test_jquery_date_field.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import datetime as dt

from django.forms import forms

from web.forms.fields import (
FutureOnlyJqueryDateField,
JqueryDateField,
PastOnlyJqueryDateField,
)


def test_year_select_render():
field = JqueryDateField(year_select_range=10)
assert "data-year-select-range" in field.widget_attrs(field.widget)
assert field.widget_attrs(field.widget)["data-year-select-range"] == 10

# test the rendering of the widget
html = field.widget.render("name", None)
assert 'data-year-select-range="10"' in html


def test_year_select_incorrect_validation():
field = JqueryDateField(year_select_range=5)
entered_value = dt.date(2000, 1, 1)
try:
field.validate(entered_value)
except forms.ValidationError as e:
assert "Date cannot be more than 5 years in the past/future." in str(e)


def test_year_select_correct_validation():
field = JqueryDateField(year_select_range=10)
entered_value = dt.date(2021, 1, 1)
assert field.clean(entered_value) == entered_value


def test_past_only_date_field_render():
field = PastOnlyJqueryDateField()
assert "data-past-only" in field.widget_attrs(field.widget)
assert field.widget_attrs(field.widget)["data-past-only"] == "yes"

# test the rendering of the widget
html = field.widget.render("name", None)
assert 'data-past-only="yes"' in html


def test_past_only_date_field():
field = PastOnlyJqueryDateField(year_select_range=10)
try:
field.validate(dt.datetime.now() + dt.timedelta(days=400))
except forms.ValidationError as e:
assert "Date cannot be in the future." in str(e)


def test_future_only_date_field_render():
field = FutureOnlyJqueryDateField()
assert "data-future-only" in field.widget_attrs(field.widget)
assert field.widget_attrs(field.widget)["data-future-only"] == "yes"

# test the rendering of the widget
html = field.widget.render("name", None)
assert 'data-future-only="yes"' in html


def test_future_only_date_field():
field = FutureOnlyJqueryDateField(year_select_range=10)
try:
field.validate(dt.datetime.now() - dt.timedelta(days=400))
except forms.ValidationError as e:
assert "Date cannot be in the past." in str(e)

0 comments on commit d3b181b

Please sign in to comment.