Skip to content

Commit

Permalink
GH-101: Don't allow scheme to be completed
Browse files Browse the repository at this point in the history
  • Loading branch information
markhobson committed Apr 8, 2024
1 parent c8eef94 commit 241e531
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 43 deletions.
13 changes: 1 addition & 12 deletions schemes/views/schemes/milestones.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,6 @@ class ChangeMilestoneDatesForm(FlaskForm): # type: ignore
required_message="Enter a construction completed planned date",
invalid_message="Construction completed planned date must be a real date",
)
construction_completed_actual = MilestoneDateField(
required_message="Enter a construction completed actual date",
invalid_message="Construction completed actual date must be a real date",
)

@classmethod
def from_domain(cls, milestones: SchemeMilestones) -> ChangeMilestoneDatesForm:
Expand Down Expand Up @@ -181,9 +177,6 @@ def from_domain(cls, milestones: SchemeMilestones) -> ChangeMilestoneDatesForm:
construction_completed_planned=milestones.get_current_status_date(
Milestone.CONSTRUCTION_COMPLETED, ObservationType.PLANNED
),
construction_completed_actual=milestones.get_current_status_date(
Milestone.CONSTRUCTION_COMPLETED, ObservationType.ACTUAL
),
)

def update_domain(self, milestones: SchemeMilestones, now: datetime) -> None:
Expand Down Expand Up @@ -213,11 +206,7 @@ def update_milestone(planned: date | None, actual: date | None, milestone: Miles
self.construction_started_actual.data,
Milestone.CONSTRUCTION_STARTED,
)
update_milestone(
self.construction_completed_planned.data,
self.construction_completed_actual.data,
Milestone.CONSTRUCTION_COMPLETED,
)
update_milestone(self.construction_completed_planned.data, None, Milestone.CONSTRUCTION_COMPLETED)


@dataclass(frozen=True)
Expand Down
22 changes: 12 additions & 10 deletions schemes/views/templates/scheme/milestones.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ <h1 class="govuk-heading-l govuk-!-margin-bottom-3">Change milestone dates</h1>
{{ milestone("Preliminary design completed", form.preliminary_design_completed_planned, form.preliminary_design_completed_actual) }}
{{ milestone("Detailed design completed", form.detailed_design_completed_planned, form.detailed_design_completed_actual) }}
{{ milestone("Construction started", form.construction_started_planned, form.construction_started_actual) }}
{{ milestone("Construction completed", form.construction_completed_planned, form.construction_completed_actual) }}
{{ milestone("Construction completed", form.construction_completed_planned, None) }}

<div class="govuk-button-group">
{{ govukButton({
Expand All @@ -71,15 +71,17 @@ <h2 class="govuk-heading-m">{{ name }}</h2>
}
}) }}
</div>
<div class="govuk-grid-column-one-half">
{{ actual_field(params={
"fieldset": {
"describedBy": "date-hint",
"legend": {
"text": "Actual date"
{% if actual_field %}
<div class="govuk-grid-column-one-half">
{{ actual_field(params={
"fieldset": {
"describedBy": "date-hint",
"legend": {
"text": "Actual date"
}
}
}
}) }}
</div>
}) }}
</div>
{% endif %}
</div>
{%- endmacro %}
3 changes: 2 additions & 1 deletion tests/integration/pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,8 @@ def __init__(self, heading: Tag):
grid_row = heading.find_next_sibling("div", class_="govuk-grid-row")
assert isinstance(grid_row, Tag)
self.planned = DateComponent(one(grid_row.select("fieldset:has(legend:-soup-contains('Planned date'))")))
self.actual = DateComponent(one(grid_row.select("fieldset:has(legend:-soup-contains('Actual date'))")))
actual_tag = grid_row.select_one("fieldset:has(legend:-soup-contains('Actual date'))")
self.actual = DateComponent(actual_tag) if actual_tag else None


class DateComponent:
Expand Down
33 changes: 18 additions & 15 deletions tests/integration/test_scheme_milestones.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,20 +151,24 @@ def test_milestones_form_shows_fields(self, schemes: SchemeRepository, client: F
assert (
change_milestone_dates_page.form.feasibility_design_completed.planned.name
== "feasibility_design_completed_planned"
and change_milestone_dates_page.form.feasibility_design_completed.actual
and change_milestone_dates_page.form.feasibility_design_completed.actual.name
== "feasibility_design_completed_actual"
and change_milestone_dates_page.form.preliminary_design_completed.planned.name
== "preliminary_design_completed_planned"
and change_milestone_dates_page.form.preliminary_design_completed.actual
and change_milestone_dates_page.form.preliminary_design_completed.actual.name
== "preliminary_design_completed_actual"
and change_milestone_dates_page.form.detailed_design_completed.planned.name
== "detailed_design_completed_planned"
and change_milestone_dates_page.form.detailed_design_completed.actual
and change_milestone_dates_page.form.detailed_design_completed.actual.name
== "detailed_design_completed_actual"
and change_milestone_dates_page.form.construction_started.planned.name == "construction_started_planned"
and change_milestone_dates_page.form.construction_started.actual
and change_milestone_dates_page.form.construction_started.actual.name == "construction_started_actual"
and change_milestone_dates_page.form.construction_completed.planned.name == "construction_completed_planned"
and change_milestone_dates_page.form.construction_completed.actual.name == "construction_completed_actual"
and change_milestone_dates_page.form.construction_completed.actual is None
)

def test_milestones_form_shows_date(self, schemes: SchemeRepository, client: FlaskClient) -> None:
Expand All @@ -174,7 +178,7 @@ def test_milestones_form_shows_date(self, schemes: SchemeRepository, client: Fla
id_=1,
effective=DateRange(datetime(2020, 1, 1, 12), None),
milestone=Milestone.CONSTRUCTION_STARTED,
observation_type=ObservationType.ACTUAL,
observation_type=ObservationType.PLANNED,
status_date=date(2020, 1, 2),
source=DataSource.ATF4_BID,
)
Expand All @@ -184,7 +188,7 @@ def test_milestones_form_shows_date(self, schemes: SchemeRepository, client: Fla
change_milestone_dates_page = ChangeMilestoneDatesPage.open(client, id_=1)

assert change_milestone_dates_page.title == "Update your capital schemes - Active Travel England - GOV.UK"
assert change_milestone_dates_page.form.construction_started.actual.value == "2 1 2020"
assert change_milestone_dates_page.form.construction_started.planned.value == "2 1 2020"

def test_milestones_form_shows_confirm(self, schemes: SchemeRepository, client: FlaskClient) -> None:
schemes.add(build_scheme(id_=1, name="Wirral Package", authority_id=1))
Expand Down Expand Up @@ -234,15 +238,15 @@ def test_milestones_updates_milestones(
id_=1,
effective=DateRange(datetime(2020, 1, 1, 12), None),
milestone=Milestone.CONSTRUCTION_STARTED,
observation_type=ObservationType.ACTUAL,
observation_type=ObservationType.PLANNED,
status_date=date(2020, 1, 2),
source=DataSource.ATF4_BID,
)
)
schemes.add(scheme)

client.post(
"/schemes/1/milestones", data={"csrf_token": csrf_token, "construction_started_actual": ["3", "1", "2020"]}
"/schemes/1/milestones", data={"csrf_token": csrf_token, "construction_started_planned": ["3", "1", "2020"]}
)

actual_scheme = schemes.get(1)
Expand All @@ -254,7 +258,7 @@ def test_milestones_updates_milestones(
assert (
milestone_revision2.effective == DateRange(datetime(2020, 2, 1, 13), None)
and milestone_revision2.milestone == Milestone.CONSTRUCTION_STARTED
and milestone_revision2.observation_type == ObservationType.ACTUAL
and milestone_revision2.observation_type == ObservationType.PLANNED
and milestone_revision2.status_date == date(2020, 1, 3)
and milestone_revision2.source == DataSource.AUTHORITY_UPDATE
)
Expand All @@ -275,7 +279,7 @@ def test_cannot_milestones_when_error(
id_=1,
effective=DateRange(datetime(2020, 1, 1, 12), None),
milestone=Milestone.CONSTRUCTION_STARTED,
observation_type=ObservationType.ACTUAL,
observation_type=ObservationType.PLANNED,
status_date=date(2020, 1, 2),
source=DataSource.ATF4_BID,
)
Expand All @@ -286,21 +290,21 @@ def test_cannot_milestones_when_error(
client.post(
"/schemes/1/milestones",
data=self.empty_change_milestone_dates_form()
| {"csrf_token": csrf_token, "construction_started_actual": ["x", "x", "x"]},
| {"csrf_token": csrf_token, "construction_started_planned": ["x", "x", "x"]},
)
)

assert (
change_milestone_dates_page.title == "Error: Update your capital schemes - Active Travel England - GOV.UK"
)
assert change_milestone_dates_page.errors and list(change_milestone_dates_page.errors) == [
"Construction started actual date must be a real date"
"Construction started planned date must be a real date"
]
assert (
change_milestone_dates_page.form.construction_started.actual.is_errored
and change_milestone_dates_page.form.construction_started.actual.error
== "Error: Construction started actual date must be a real date"
and change_milestone_dates_page.form.construction_started.actual.value == "x x x"
change_milestone_dates_page.form.construction_started.planned.is_errored
and change_milestone_dates_page.form.construction_started.planned.error
== "Error: Construction started planned date must be a real date"
and change_milestone_dates_page.form.construction_started.planned.value == "x x x"
)
actual_scheme = schemes.get(1)
assert actual_scheme
Expand All @@ -310,7 +314,7 @@ def test_cannot_milestones_when_error(
milestone_revision1.id == 1
and milestone_revision1.effective == DateRange(datetime(2020, 1, 1, 12), None)
and milestone_revision1.milestone == Milestone.CONSTRUCTION_STARTED
and milestone_revision1.observation_type == ObservationType.ACTUAL
and milestone_revision1.observation_type == ObservationType.PLANNED
and milestone_revision1.status_date == date(2020, 1, 2)
and milestone_revision1.source == DataSource.ATF4_BID
)
Expand Down Expand Up @@ -381,5 +385,4 @@ def empty_change_milestone_dates_form(self) -> dict[str, list[str]]:
"construction_started_planned": empty_date,
"construction_started_actual": empty_date,
"construction_completed_planned": empty_date,
"construction_completed_actual": empty_date,
}
21 changes: 16 additions & 5 deletions tests/views/schemes/test_milestones.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,6 @@ class TestChangeMilestoneDatesForm:
"construction_started_planned",
"construction_started_actual",
"construction_completed_planned",
"construction_completed_actual",
]
field_names_milestones_observation_types = [
("feasibility_design_completed_planned", Milestone.FEASIBILITY_DESIGN_COMPLETED, ObservationType.PLANNED),
Expand All @@ -189,7 +188,6 @@ class TestChangeMilestoneDatesForm:
("construction_started_planned", Milestone.CONSTRUCTION_STARTED, ObservationType.PLANNED),
("construction_started_actual", Milestone.CONSTRUCTION_STARTED, ObservationType.ACTUAL),
("construction_completed_planned", Milestone.CONSTRUCTION_COMPLETED, ObservationType.PLANNED),
("construction_completed_actual", Milestone.CONSTRUCTION_COMPLETED, ObservationType.ACTUAL),
]

@pytest.mark.parametrize("field_name, milestone, observation_type", field_names_milestones_observation_types)
Expand Down Expand Up @@ -233,7 +231,6 @@ def test_from_domain_when_minimal(self) -> None:
and form.construction_started_planned.data is None
and form.construction_started_actual.data is None
and form.construction_completed_planned.data is None
and form.construction_completed_actual.data is None
)

@pytest.mark.parametrize("field_name, milestone, observation_type", field_names_milestones_observation_types)
Expand Down Expand Up @@ -329,6 +326,22 @@ def test_update_domain_ignores_unchanged_dates(
and milestone_revision1.source == DataSource.ATF4_BID
)

def test_update_domain_ignores_construction_completed_actual_date(self) -> None:
form = ChangeMilestoneDatesForm(
formdata=MultiDict(
[
("construction_completed_actual", "2"),
("construction_completed_actual", "1"),
("construction_completed_actual", "2020"),
]
)
)
milestones = SchemeMilestones()

form.update_domain(milestones, now=datetime(2020, 2, 1, 13))

assert not milestones.milestone_revisions

@pytest.mark.parametrize("field_name", field_names)
def test_no_errors_when_valid(self, field_name: str) -> None:
form = ChangeMilestoneDatesForm(
Expand Down Expand Up @@ -361,7 +374,6 @@ def test_date_without_initial_value_is_optional(self, field_name: str) -> None:
("construction_started_planned", "Enter a construction started planned date"),
("construction_started_actual", "Enter a construction started actual date"),
("construction_completed_planned", "Enter a construction completed planned date"),
("construction_completed_actual", "Enter a construction completed actual date"),
],
)
@pytest.mark.parametrize(
Expand Down Expand Up @@ -398,7 +410,6 @@ def test_date_with_initial_value_is_required(
("construction_started_planned", "Construction started planned date must be a real date"),
("construction_started_actual", "Construction started actual date must be a real date"),
("construction_completed_planned", "Construction completed planned date must be a real date"),
("construction_completed_actual", "Construction completed actual date must be a real date"),
],
)
@pytest.mark.parametrize(
Expand Down

0 comments on commit 241e531

Please sign in to comment.