Skip to content

Commit

Permalink
Merge pull request #2260 from uktrade/LTD-5706-approve-session-wizard
Browse files Browse the repository at this point in the history
[LTD-5706] convert advice form and views into structured folders.
  • Loading branch information
Tllew authored Dec 10, 2024
2 parents 867f322 + 09256a6 commit d3fb86f
Show file tree
Hide file tree
Showing 32 changed files with 1,072 additions and 945 deletions.
2 changes: 2 additions & 0 deletions caseworker/advice/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,7 @@ class AdviceType:

class AdviceSteps:
RECOMMEND_APPROVAL = "recommend_approval"
DESNZ_APPROVAL = "desnz_approval"
FCDO_APPROVAL = "fcdo_approval"
LICENCE_CONDITIONS = "licence_conditions"
LICENCE_FOOTNOTES = "licence_footnotes"
651 changes: 0 additions & 651 deletions caseworker/advice/forms.py

This file was deleted.

180 changes: 180 additions & 0 deletions caseworker/advice/forms/approval.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
from django import forms

from core.common.forms import BaseForm
from crispy_forms_gds.helper import FormHelper
from crispy_forms_gds.layout import Layout, Submit
from crispy_forms_gds.choices import Choice

from core.forms.layouts import (
ConditionalCheckboxes,
ConditionalCheckboxesQuestion,
RadioTextArea,
)


class SelectAdviceForm(forms.Form):
CHOICES = [("approve_all", "Approve all"), ("refuse_all", "Refuse all")]

recommendation = forms.ChoiceField(
choices=CHOICES,
widget=forms.RadioSelect,
label="",
error_messages={"required": "Select if you approve all or refuse all"},
)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.add_input(Submit("submit", "Continue"))


class PicklistAdviceForm(forms.Form):
def _picklist_to_choices(self, picklist_data):
reasons_choices = []
reasons_text = {"other": ""}

for result in picklist_data["results"]:
key = "_".join(result.get("name").lower().split())
choice = Choice(key, result.get("name"))
if result == picklist_data["results"][-1]:
choice = Choice(key, result.get("name"), divider="or")
reasons_choices.append(choice)
reasons_text[key] = result.get("text")
reasons_choices.append(Choice("other", "Other"))
return reasons_choices, reasons_text


class MoveCaseForwardForm(forms.Form):
def __init__(self, move_case_button_label="Move case forward", *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(Submit("submit", move_case_button_label, css_id="move-case-forward-button"))


class RecommendAnApprovalForm(PicklistAdviceForm, BaseForm):
class Layout:
TITLE = "Recommend an approval"

approval_reasons = forms.CharField(
widget=forms.Textarea(attrs={"rows": 7, "class": "govuk-!-margin-top-4"}),
label="",
error_messages={"required": "Enter a reason for approving"},
)
approval_radios = forms.ChoiceField(
label="What is your reason for approving?",
required=False,
widget=forms.RadioSelect,
choices=(),
)
add_licence_conditions = forms.BooleanField(
label="Add licence conditions, instructions to exporter or footnotes (optional)",
required=False,
)

def __init__(self, *args, **kwargs):
approval_reason = kwargs.pop("approval_reason")
# this follows the same pattern as denial_reasons.
approval_choices, approval_text = self._picklist_to_choices(approval_reason)
self.approval_text = approval_text
super().__init__(*args, **kwargs)

self.fields["approval_radios"].choices = approval_choices

def get_layout_fields(self):
return (
RadioTextArea("approval_radios", "approval_reasons", self.approval_text),
"add_licence_conditions",
)


class LicenceConditionsForm(PicklistAdviceForm, BaseForm):
class Layout:
TITLE = "Add licence conditions, instructions to exporter or footnotes (optional)"

proviso = forms.CharField(
widget=forms.Textarea(attrs={"rows": 7, "class": "govuk-!-margin-top-4"}),
label="",
required=False,
)

approval_radios = forms.ChoiceField(
label="What is your reason for approving?",
required=False,
widget=forms.RadioSelect,
choices=(),
)
proviso_checkboxes = forms.MultipleChoiceField(
label="Add a licence condition (optional)",
required=False,
widget=forms.CheckboxSelectMultiple,
choices=(),
)

def clean(self):
cleaned_data = super().clean()
# only return proviso (text) for selected radios, nothing else matters, join by 2 newlines
return {"proviso": "\r\n\r\n".join([cleaned_data[selected] for selected in cleaned_data["proviso_checkboxes"]])}

def __init__(self, *args, **kwargs):
proviso = kwargs.pop("proviso")

proviso_choices, proviso_text = self._picklist_to_choices(proviso)
self.proviso_text = proviso_text

self.conditional_checkbox_choices = (
ConditionalCheckboxesQuestion(choices.label, choices.value) for choices in proviso_choices
)

super().__init__(*args, **kwargs)

self.fields["proviso_checkboxes"].choices = proviso_choices
for choices in proviso_choices:
self.fields[choices.value] = forms.CharField(
widget=forms.Textarea(attrs={"rows": 3, "class": "govuk-!-margin-top-4"}),
label="Description",
required=False,
initial=proviso_text[choices.value],
)

def get_layout_fields(self):

return (ConditionalCheckboxes("proviso_checkboxes", *self.conditional_checkbox_choices),)


class FootnotesApprovalAdviceForm(PicklistAdviceForm, BaseForm):
class Layout:
TITLE = "Instructions for the exporter (optional)"

instructions_to_exporter = forms.CharField(
widget=forms.Textarea(attrs={"rows": "3"}),
label="Add any instructions for the exporter (optional)",
help_text="These may be added to the licence cover letter, subject to review by the Licensing Unit.",
required=False,
)

footnote_details_radios = forms.ChoiceField(
label="Add a reporting footnote (optional)",
required=False,
widget=forms.RadioSelect,
choices=(),
)
footnote_details = forms.CharField(
widget=forms.Textarea(attrs={"rows": 3, "class": "govuk-!-margin-top-4"}),
label="",
required=False,
)

def __init__(self, *args, **kwargs):
footnote_details = kwargs.pop("footnote_details")
footnote_details_choices, footnote_text = self._picklist_to_choices(footnote_details)
self.footnote_text = footnote_text

super().__init__(*args, **kwargs)

self.fields["footnote_details_radios"].choices = footnote_details_choices

def get_layout_fields(self):
return (
"instructions_to_exporter",
RadioTextArea("footnote_details_radios", "footnote_details", self.footnote_text),
)
69 changes: 69 additions & 0 deletions caseworker/advice/forms/consolidate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from django import forms
from django.utils.html import format_html

from caseworker.advice.forms.approval import SelectAdviceForm
from caseworker.advice.forms.forms import GiveApprovalAdviceForm
from crispy_forms_gds.helper import FormHelper
from crispy_forms_gds.layout import Layout, Submit

from core.forms.layouts import (
RadioTextArea,
)


class ConsolidateSelectAdviceForm(SelectAdviceForm):
DOCUMENT_TITLE = "Recommend and combine case recommendation case"
CHOICES = [("approve", "Approve"), ("refuse", "Refuse")]
recommendation = forms.ChoiceField(
choices=CHOICES,
widget=forms.RadioSelect,
label="",
error_messages={"required": "Select if you approve or refuse"},
)

def __init__(self, team_name, *args, **kwargs):
super().__init__(*args, **kwargs)

recommendation_label = "What is the combined recommendation"
if team_name:
recommendation_label = f"{recommendation_label} for {team_name}"
self.fields["recommendation"].label = f"{recommendation_label}?"


class ConsolidateApprovalForm(GiveApprovalAdviceForm):
"""Approval form minus some fields."""

def __init__(self, team_alias, *args, **kwargs):
super().__init__(*args, **kwargs)

self.helper = FormHelper()
self.helper.layout = Layout(
RadioTextArea("approval_radios", "approval_reasons", self.approval_text),
RadioTextArea("proviso_radios", "proviso", self.proviso_text),
Submit("submit", "Submit recommendation"),
)


class LUConsolidateRefusalForm(forms.Form):
refusal_note = forms.CharField(
widget=forms.Textarea(attrs={"rows": "7"}),
label="Enter the refusal note as agreed in the refusal meeting",
error_messages={"required": "Enter the refusal meeting note"},
)

denial_reasons = forms.MultipleChoiceField(
widget=forms.SelectMultiple(),
label="What is the refusal criteria?",
help_text=format_html(
f'Select all <a class="govuk-link" '
f'href="https://questions-statements.parliament.uk/written-statements/detail/2021-12-08/hcws449" '
f'target="_blank">refusal criteria (opens in a new tab)</a> that apply'
),
error_messages={"required": "Select at least one refusal criteria"},
)

def __init__(self, choices, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["denial_reasons"].choices = choices
self.helper = FormHelper()
self.helper.layout = Layout("denial_reasons", "refusal_note", Submit("submit", "Submit recommendation"))
75 changes: 75 additions & 0 deletions caseworker/advice/forms/countersign.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
from django import forms

from crispy_forms_gds.helper import FormHelper
from crispy_forms_gds.layout import Field, Layout

from core.forms.layouts import (
ConditionalRadios,
ConditionalRadiosQuestion,
)
from core.forms.utils import coerce_str_to_bool


class CountersignAdviceForm(forms.Form):
DOCUMENT_TITLE = "Review and countersign this case"
approval_reasons = forms.CharField(
widget=forms.Textarea(attrs={"rows": "10"}),
label="Explain why you are agreeing with this recommendation",
error_messages={"required": "Enter why you agree with the recommendation"},
)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.layout = Layout("approval_reasons")


class CountersignDecisionAdviceForm(forms.Form):
DECISION_CHOICES = [(True, "Yes"), (False, "No")]

outcome_accepted = forms.TypedChoiceField(
choices=DECISION_CHOICES,
widget=forms.RadioSelect,
coerce=coerce_str_to_bool,
label="Do you agree with this recommendation?",
error_messages={"required": "Select yes if you agree with the recommendation"},
)
approval_reasons = forms.CharField(
widget=forms.Textarea(attrs={"rows": "10"}),
label="Explain your reasons",
required=False,
)
rejected_reasons = forms.CharField(
widget=forms.Textarea(attrs={"rows": "10"}),
label="Message to the case officer (explaining why the case is being returned)",
required=False,
)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.layout = Layout(
ConditionalRadios(
"outcome_accepted",
ConditionalRadiosQuestion("Yes", Field("approval_reasons")),
ConditionalRadiosQuestion("No", Field("rejected_reasons")),
),
)

def clean_approval_reasons(self):
outcome_accepted = self.cleaned_data.get("outcome_accepted")
approval_reasons = self.cleaned_data.get("approval_reasons")
if outcome_accepted and not self.cleaned_data.get("approval_reasons"):
self.add_error("approval_reasons", "Enter a reason for countersigning")

return approval_reasons

def clean_rejected_reasons(self):
outcome_accepted = self.cleaned_data.get("outcome_accepted")
rejected_reasons = self.cleaned_data.get("rejected_reasons")
if outcome_accepted is False and not self.cleaned_data.get("rejected_reasons"):
self.add_error("rejected_reasons", "Enter a message explaining why the case is being returned")

return rejected_reasons
11 changes: 11 additions & 0 deletions caseworker/advice/forms/delete.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from django import forms

from crispy_forms_gds.helper import FormHelper
from crispy_forms_gds.layout import Submit


class DeleteAdviceForm(forms.Form):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.add_input(Submit("confirm", "Confirm"))
20 changes: 20 additions & 0 deletions caseworker/advice/forms/edit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from django import forms

from core.common.forms import BaseForm


class PicklistApprovalAdviceEditForm(BaseForm):
class Layout:
TITLE = "Add licence conditions, instructions to exporter or footnotes (optional)"

proviso = forms.CharField(
widget=forms.Textarea(attrs={"rows": 30, "class": "govuk-!-margin-top-4"}),
label="",
required=False,
)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def get_layout_fields(self):
return ("proviso",)
Loading

0 comments on commit d3fb86f

Please sign in to comment.