Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TP2000-1067 Fix measure editing footnote save #1050

Merged
merged 9 commits into from
Oct 3, 2023
4 changes: 4 additions & 0 deletions measures/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ class MeasureEditSteps(models.TextChoices):
"geographical_area_exclusions",
"Geographical area exclusions",
)


MEASURE_CONDITIONS_FORMSET_PREFIX = "measure-conditions-formset"
MEASURE_COMMODITIES_FORMSET_PREFIX = "measure_commodities_duties_formset"
27 changes: 18 additions & 9 deletions measures/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
from geo_areas.models import GeographicalArea
from geo_areas.utils import get_all_members_of_geo_groups
from measures import models
from measures.constants import MEASURE_COMMODITIES_FORMSET_PREFIX
from measures.constants import MEASURE_CONDITIONS_FORMSET_PREFIX
from measures.constants import MeasureEditSteps
from measures.models import MeasureExcludedGeographicalArea
from measures.parsers import DutySentenceParser
Expand All @@ -58,9 +60,6 @@

logger = logging.getLogger(__name__)

MEASURE_CONDITIONS_FORMSET_PREFIX = "measure-conditions-formset"
MEASURE_COMMODITIES_FORMSET_PREFIX = "measure_commodities_duties_formset"


class MeasureGeoAreaInitialDataMixin(FormSetSubmitMixin):
def get_geo_area_initial(self):
Expand Down Expand Up @@ -613,10 +612,8 @@ def clean(self):
return cleaned_data

def save(self, commit=True):
"""Get the measure instance after form submission, get from session
storage any footnote pks created via the Footnote formset and any pks
not removed from the measure after editing and create footnotes via
FootnoteAssociationMeasure."""
"""Updates a measure instance's geographical area and exclusions,
duties, and footnote associations following form submission."""
instance = super().save(commit=False)
if commit:
instance.save()
Expand Down Expand Up @@ -692,10 +689,22 @@ def save(self, commit=True):
"component_measure",
)

# Footnotes added via "Add another footnote" button
footnote_pks = [
dct["footnote"]
for dct in self.request.session.get(f"formset_initial_{sid}", [])
form["footnote"]
for form in self.request.session.get(f"formset_initial_{sid}", [])
]

# Footnote submitted directly via "Save" button
if hasattr(self.request, "POST"):
dalecannon marked this conversation as resolved.
Show resolved Hide resolved
form_footnote = self.request.POST.get(
f"form-{len(footnote_pks)}-footnote",
None,
)
if form_footnote:
footnote_pks.append(form_footnote)

# Footnotes already on measure
footnote_pks.extend(self.request.session.get(f"instance_footnotes_{sid}", []))

self.request.session.pop(f"formset_initial_{sid}", None)
Expand Down
87 changes: 41 additions & 46 deletions measures/jinja2/measures/create-footnotes-formset.jinja
Original file line number Diff line number Diff line change
@@ -1,51 +1,46 @@
{% with form_footnotes = form.request.session["instance_footnotes_" ~ form.instance.sid] %}
{% if form_footnotes %}
{% set table_rows = [] %}
{% for footnote in footnotes %}
{% if footnote.pk in form.request.session["instance_footnotes_"~form.instance.sid]%}
{% set footnote_link -%}
<a class="govuk-link govuk-!-font-weight-bold" href="{{ footnote.get_url() }}">{{ footnote|string }}</a>
{%- endset %}
{% set remove_button -%}
<button formaction={{ form.instance.get_url('edit-footnotes') }} class="govuk-link govuk-!-font-weight-bold fake-link" name="remove" value={{ footnote.pk }}>Remove</a>
{%- endset %}
{{ table_rows.append([
{"html": footnote_link},
{"text": footnote.get_description().description|default("")},
{"html": remove_button}
]) or "" }}
{% endif %}
{% endfor %}
{{ govukTable({
"head": [
{"text": "ID"},
{"text": "Description"},
{"text": ""}
],
"rows": table_rows,
"caption": "Footnotes currently assigned to the measure",
"captionClasses": "govuk-table__caption--m"
}) }}
{% else %}
<p class="govuk-label">No footnotes found.</p>
<br></br>
{% endif %}
{% with measure_footnotes = form.request.session["instance_footnotes_" ~ form.instance.sid] %}
{% if measure_footnotes %}
{% set table_rows = [] %}
{% for footnote in footnotes %}
{% if footnote.pk in measure_footnotes %}
{% set footnote_link -%}
<a class="govuk-link govuk-!-font-weight-bold" href="{{ footnote.get_url() }}">{{ footnote|string }}</a>
{%- endset %}
{% set remove_button -%}
<button formaction={{ form.instance.get_url('edit-footnotes') }} class="govuk-link govuk-!-font-weight-bold fake-link" name="remove" value={{ footnote.pk }}>Remove</a>
{%- endset %}
{{ table_rows.append([
{"html": footnote_link},
{"text": footnote.get_description().description|default("")},
{"html": remove_button}
]) or "" }}
{% endif %}
{% endfor %}
{{ govukTable({
"head": [
{"text": "ID"},
{"text": "Description"},
{"text": ""}
],
"rows": table_rows,
"caption": "Footnotes currently assigned to the measure",
"captionClasses": "govuk-table__caption--m"
}) }}
{% endif %}
{% endwith %}

{{ crispy(footnotes_formset.management_form, no_form_tags) }}
<label class="govuk-label">Add a footnote</label>
<div id="sort-code-hint" class="govuk-hint">Start typing the ID of the footnote or terms used in the description</div>
{% for form in footnotes_formset %}
{{ crispy(form) }}
{% endfor %}

{% if footnotes_formset.data[footnotes_formset.prefix ~ "-ADD"] %}
{{ crispy(footnotes_formset.empty_form)|replace("__prefix__", footnotes_formset.forms|length)|safe }}
{% endif %}
{% for form in footnotes_formset %}
{{ crispy(form) }}
{% endfor %}

{% if footnotes_formset.data[footnotes_formset.prefix ~ "-ADD"] %}
{{ crispy(footnotes_formset.empty_form)|replace("__prefix__", footnotes_formset.forms|length)|safe }}
{% endif %}

{% call govukFieldset({"legend": {}, "classes": "govuk-!-padding-top-3"}) %}
<button class="govuk-button govuk-button--secondary" data-module="govuk-button" value=1, name={{ footnotes_formset.prefix ~ "-ADD" }}, formaction={{ object.get_url("edit-footnotes") }}>
Add another footnote
</button

{% endcall %}
{% call govukFieldset({"legend": {}, "classes": "govuk-!-padding-top-3"}) %}
<button class="govuk-button govuk-button--secondary" data-module="govuk-button" value=1, name={{ footnotes_formset.prefix ~ "-ADD" }}, formaction={{ object.get_url("edit-footnotes") }}>
Add another footnote
</button
{% endcall %}
2 changes: 1 addition & 1 deletion measures/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from common.validators import ApplicabilityCode
from common.validators import UpdateType
from geo_areas.validators import AreaCode
from measures.forms import MEASURE_CONDITIONS_FORMSET_PREFIX
from measures.constants import MEASURE_CONDITIONS_FORMSET_PREFIX
from measures.forms import MeasureForm
from measures.models import Measure
from measures.models import MeasureAction
Expand Down
4 changes: 2 additions & 2 deletions measures/tests/test_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
from geo_areas import constants
from geo_areas.validators import AreaCode
from measures import forms
from measures.forms import MEASURE_COMMODITIES_FORMSET_PREFIX
from measures.forms import MEASURE_CONDITIONS_FORMSET_PREFIX
from measures.constants import MEASURE_COMMODITIES_FORMSET_PREFIX
from measures.constants import MEASURE_CONDITIONS_FORMSET_PREFIX
from measures.forms import MeasureConditionsFormSet
from measures.forms import MeasureEndDateForm
from measures.forms import MeasureForm
Expand Down
25 changes: 25 additions & 0 deletions measures/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,31 @@ def test_measure_update_get_footnotes(session_with_workbasket):
assert len(footnotes) == 0


def test_measure_update_form_creates_footnote_association(
measure_form,
valid_user_client,
):
"""Test that editing a measure to add a new footnote doesn't require
pressing "Add another footnote" button before submitting (saving) the
form."""
footnote = factories.FootnoteFactory.create()
measure = measure_form.instance
assert not measure.footnotes.exists()

form_data = {k: v for k, v in measure_form.data.items() if v is not None}
# Add footnote to form data and not to "formset_initial" in session data (i.e not pressing "Add another footnote")
form_data["form-0-footnote"] = footnote.pk

url = reverse("measure-ui-edit", kwargs={"sid": measure.sid})
response = valid_user_client.post(url, form_data)
assert response.status_code == 302

assert FootnoteAssociationMeasure.objects.filter(
footnoted_measure__sid=measure.sid,
associated_footnote=footnote,
).exists()


# https://uktrade.atlassian.net/browse/TP2000-340
def test_measure_update_updates_footnote_association(measure_form, client, valid_user):
"""Tests that when updating a measure with an existing footnote the
Expand Down
16 changes: 8 additions & 8 deletions measures/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@
from geo_areas.models import GeographicalArea
from geo_areas.utils import get_all_members_of_geo_groups
from measures import forms
from measures.constants import MEASURE_CONDITIONS_FORMSET_PREFIX
from measures.constants import START
from measures.constants import MeasureEditSteps
from measures.filters import MeasureFilter
from measures.filters import MeasureTypeFilterBackend
from measures.forms import MEASURE_CONDITIONS_FORMSET_PREFIX
from measures.models import FootnoteAssociationMeasure
from measures.models import Measure
from measures.models import MeasureActionPair
Expand Down Expand Up @@ -972,20 +972,20 @@ def get_conditions(self, measure):

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
initial = self.request.session.get(
context["no_form_tags"] = FormHelper()
context["no_form_tags"].form_tag = False

formset_footnotes = self.request.session.get(
f"formset_initial_{self.kwargs.get('sid')}",
[],
)
footnotes_formset = forms.MeasureUpdateFootnotesFormSet()
footnotes_formset.initial = initial
footnotes_formset.initial = formset_footnotes
footnotes_formset.form_kwargs = {"path": self.request.path}
context["footnotes_formset"] = footnotes_formset
context["no_form_tags"] = FormHelper()
context["no_form_tags"].form_tag = False
context["footnotes"] = self.get_footnotes(context["measure"])

conditions_initial = []

if self.request.POST:
conditions_initial = unprefix_formset_data(
MEASURE_CONDITIONS_FORMSET_PREFIX,
Expand All @@ -994,12 +994,12 @@ def get_context_data(self, **kwargs):
conditions_formset = forms.MeasureConditionsFormSet(
self.request.POST,
initial=conditions_initial,
prefix="measure-conditions-formset",
prefix=MEASURE_CONDITIONS_FORMSET_PREFIX,
)
else:
conditions_formset = forms.MeasureConditionsFormSet(
initial=conditions_initial,
prefix="measure-conditions-formset",
prefix=MEASURE_CONDITIONS_FORMSET_PREFIX,
)
conditions = self.get_conditions(context["measure"])
form_fields = conditions_formset.form.Meta.fields
Expand Down
Loading