diff --git a/README.md b/README.md index d7fe6d28..3d15d8c7 100644 --- a/README.md +++ b/README.md @@ -56,8 +56,8 @@ Django will provide the local url which should be http://127.0.0.1:8000/, naviga ### Django Along with the above runserver command, while developing on the project, \ the following will be handy when making changes to the db model:\ -`pipenv run python manage.py makemigrations`\ -`pipenv run python manage.py migrate` +`invoke makemigrations`\ +`invoke migrate` ### Dependencies To add a new dependency to the project, use the following command:\ diff --git a/report_a_breach/admin.py b/report_a_breach/admin.py index 8c38f3f3..af1b9045 100644 --- a/report_a_breach/admin.py +++ b/report_a_breach/admin.py @@ -1,3 +1,6 @@ from django.contrib import admin +from report_a_breach.core.models import SanctionsRegime + # Register your models here. +admin.site.register(SanctionsRegime) diff --git a/report_a_breach/base_classes/views.py b/report_a_breach/base_classes/views.py index bb12beb4..e44b829b 100644 --- a/report_a_breach/base_classes/views.py +++ b/report_a_breach/base_classes/views.py @@ -37,7 +37,7 @@ def get_context_data(self, form, **kwargs): context = super().get_context_data(form=form, **kwargs) if custom_getter := getattr(self, f"get_{self.steps.current}_context_data", None): context.update(custom_getter(form)) - return super().get_context_data(form=form, **kwargs) + return context def process_step(self, form): if custom_getter := getattr(self, f"process_{self.steps.current}_step", None): diff --git a/report_a_breach/core/forms.py b/report_a_breach/core/forms.py index 28ed3997..ceb72462 100644 --- a/report_a_breach/core/forms.py +++ b/report_a_breach/core/forms.py @@ -1,8 +1,9 @@ +from crispy_forms_gds.helper import FormHelper +from crispy_forms_gds.layout import Submit from django import forms import report_a_breach.question_content as content -from report_a_breach.base_classes.forms import BaseForm -from report_a_breach.base_classes.forms import BaseModelForm +from report_a_breach.base_classes.forms import BaseForm, BaseModelForm from .models import Breach @@ -56,4 +57,7 @@ class Meta: class SummaryForm(BaseForm): - pass + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.helper = FormHelper() + self.helper.add_input(Submit("submit", "Submit and Save", css_class="btn-primary")) diff --git a/report_a_breach/core/models.py b/report_a_breach/core/models.py index 48b9465c..f686a9d5 100644 --- a/report_a_breach/core/models.py +++ b/report_a_breach/core/models.py @@ -22,10 +22,9 @@ class Breach(BaseModel): ) reporter_email_address = models.EmailField(verbose_name=EMAIL["text"]) reporter_full_name = models.TextField(verbose_name=FULL_NAME["text"]) - # TODO: temporarily commented out until the relevant form is implemented - # sanctions_regimes = models.ManyToManyField( - # "SanctionsRegime", through="SanctionsRegimeBreachThrough" - # ) + sanctions_regimes = models.ManyToManyField( + "SanctionsRegime", through="SanctionsRegimeBreachThrough" + ) additional_information = models.TextField(verbose_name=ADDITIONAL_INFORMATION["text"]) diff --git a/report_a_breach/core/urls.py b/report_a_breach/core/urls.py index c3ccb040..80cd80ee 100644 --- a/report_a_breach/core/urls.py +++ b/report_a_breach/core/urls.py @@ -1,19 +1,14 @@ -from django.urls import path -from django.urls import re_path +from django.urls import path, re_path -from .views import LandingView -from .views import ReportABreachWizardView -from .views import ReportSubmissionCompleteView -from .views import SummaryView +from .views import LandingView, ReportABreachWizardView, ReportSubmissionCompleteView report_a_breach_wizard = ReportABreachWizardView.as_view( - url_name="report_a_breach_step", done_step_name="finished" + url_name="report_a_breach_step", done_step_name="confirmation" ) urlpatterns = [ path("landing", LandingView.as_view(), name="landing"), - path("summary//", SummaryView.as_view(), name="summary"), - path("confirmation/", ReportSubmissionCompleteView.as_view(), name="confirmation"), + path("confirmation", ReportSubmissionCompleteView.as_view(), name="confirmation"), path("report_a_breach", report_a_breach_wizard, name="report_a_breach"), re_path(r"report_a_breach/(?P.+)/$", report_a_breach_wizard, name="report_a_breach_step"), ] diff --git a/report_a_breach/core/views.py b/report_a_breach/core/views.py index d9be91a1..166158e4 100644 --- a/report_a_breach/core/views.py +++ b/report_a_breach/core/views.py @@ -3,20 +3,15 @@ from django.shortcuts import render from django.urls import reverse from django.utils.crypto import get_random_string -from django.views.generic import FormView -from django.views.generic import TemplateView +from django.views.generic import FormView, TemplateView from report_a_breach.base_classes.views import BaseWizardView from report_a_breach.constants import BREADCRUMBS_START_PAGE from report_a_breach.question_content import RELATIONSHIP from report_a_breach.utils.notifier import send_mail -from .forms import EmailForm -from .forms import EmailVerifyForm -from .forms import NameForm -from .forms import StartForm -from .forms import SummaryForm -from .models import Breach +from .forms import EmailForm, EmailVerifyForm, NameForm, StartForm, SummaryForm +from .models import Breach, SanctionsRegime, SanctionsRegimeBreachThrough EMAIL_TEMPLATE_ID = os.getenv("GOVUK_NOTIFY_TEMPLATE_EMAIL_VERIFICATION") @@ -34,9 +29,13 @@ class ReportABreachWizardView(BaseWizardView): def get_summary_template_name(self): return "summary.html" - def get_summary_context_data(self, form): - context_dict = self.get_all_cleaned_data() - return context_dict + def get_summary_context_data(self, form, **kwargs): + context = self.get_all_cleaned_data() + choice_dict = dict(RELATIONSHIP["choices"]) + context["company_relationship"] = choice_dict.get( + context["reporter_professional_relationship"] + ) + return context def process_email_step(self, form): reporter_email_address = form.cleaned_data.get("reporter_email_address") @@ -58,17 +57,24 @@ def get_form_kwargs(self, step=None): def done(self, form_list, **kwargs): all_cleaned_data = self.get_all_cleaned_data() - Breach.objects.create( + sanctions_regime = SanctionsRegime.objects.get(short_name="The Russia") + new_breach = Breach.objects.create( reporter_professional_relationship=all_cleaned_data[ "reporter_professional_relationship" ], reporter_email_address=all_cleaned_data["reporter_email_address"], reporter_full_name=all_cleaned_data["reporter_full_name"], ) - return render( - self.request, - "done.html", + new_breach.additional_information = "N/A" + sanctions_breach = SanctionsRegimeBreachThrough.objects.create( + breach=new_breach, sanctions_regime=sanctions_regime ) + sanctions_breach.save() + new_breach.sanctions_regimes.add(sanctions_regime) + new_breach.save() + reference_id = str(new_breach.id).split("-")[0].upper() + kwargs["reference_id"] = reference_id + return render(self.request, "confirmation.html") class LandingView(TemplateView): @@ -145,6 +151,5 @@ class ReportSubmissionCompleteView(TemplateView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - session_data = self.request.session.get("breach_instance") - context["application_reference_number"] = session_data["reporter_confirmation_id"] + context["application_reference_number"] = kwargs["reference_id"] return context diff --git a/report_a_breach/migrations/0002_breach_personorcompany_sanctionsregime_and_more.py b/report_a_breach/migrations/0002_breach_personorcompany_sanctionsregime_and_more.py new file mode 100644 index 00000000..7e14a3ff --- /dev/null +++ b/report_a_breach/migrations/0002_breach_personorcompany_sanctionsregime_and_more.py @@ -0,0 +1,191 @@ +# Generated by Django 4.2.9 on 2024-01-29 09:10 + +import uuid + +import django.db.models.deletion +import django_countries.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("report_a_breach", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="Breach", + fields=[ + ( + "id", + models.UUIDField( + default=uuid.uuid4, editable=False, primary_key=True, serialize=False + ), + ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("modified_at", models.DateTimeField(auto_now=True)), + ( + "reporter_professional_relationship", + models.TextField( + choices=[ + ( + "owner", + "I'm an owner, officer or employee of the company, or I am the person", + ), + ( + "acting", + "I do not work for the company, but I'm acting on their behalf to make a voluntary declaration", + ), + ( + "third_party", + "I work for a third party with a legal responsibility to make a mandatory declaration", + ), + ( + "no_professional_relationship", + "I do not have a professional relationship with the company or person or I no longer have a professional relationship with them", + ), + ], + verbose_name="What is the professional relationship with the company or person suspected of breaching sanctions?", + ), + ), + ( + "reporter_email_address", + models.EmailField(max_length=254, verbose_name="What is your email address?"), + ), + ("reporter_full_name", models.TextField(verbose_name="What is your full name?")), + ( + "additional_information", + models.TextField(verbose_name="Tell us about the suspected breach"), + ), + ], + options={ + "abstract": False, + }, + ), + migrations.CreateModel( + name="PersonOrCompany", + fields=[ + ( + "id", + models.UUIDField( + default=uuid.uuid4, editable=False, primary_key=True, serialize=False + ), + ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("modified_at", models.DateTimeField(auto_now=True)), + ( + "person_or_company", + models.CharField( + choices=[("person", "Person"), ("company", "Company")], max_length=7 + ), + ), + ("name", models.TextField()), + ("website", models.URLField(null=True)), + ("address_line_1", models.TextField()), + ("address_line_2", models.TextField(null=True)), + ("address_line_3", models.TextField(null=True)), + ("address_line_4", models.TextField(null=True)), + ("town_or_city", models.TextField()), + ("county", django_countries.fields.CountryField(max_length=2)), + ("postcode", models.TextField()), + ( + "type_of_relationship", + models.CharField( + choices=[ + ("breacher", "Breacher"), + ("supplier", "Supplier"), + ("recipient", "Recipient"), + ], + max_length=9, + ), + ), + ( + "breach", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="report_a_breach.breach" + ), + ), + ], + options={ + "abstract": False, + }, + ), + migrations.CreateModel( + name="SanctionsRegime", + fields=[ + ( + "id", + models.UUIDField( + default=uuid.uuid4, editable=False, primary_key=True, serialize=False + ), + ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("modified_at", models.DateTimeField(auto_now=True)), + ("short_name", models.TextField()), + ("full_name", models.TextField()), + ], + options={ + "abstract": False, + }, + ), + migrations.CreateModel( + name="SanctionsRegimeBreachThrough", + fields=[ + ( + "id", + models.UUIDField( + default=uuid.uuid4, editable=False, primary_key=True, serialize=False + ), + ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("modified_at", models.DateTimeField(auto_now=True)), + ( + "breach", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="report_a_breach.breach" + ), + ), + ( + "sanctions_regime", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="report_a_breach.sanctionsregime", + ), + ), + ], + options={ + "abstract": False, + }, + ), + migrations.CreateModel( + name="UploadedDocument", + fields=[ + ( + "id", + models.UUIDField( + default=uuid.uuid4, editable=False, primary_key=True, serialize=False + ), + ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("modified_at", models.DateTimeField(auto_now=True)), + ("file", models.FileField(upload_to="")), + ( + "breach", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="report_a_breach.breach" + ), + ), + ], + options={ + "abstract": False, + }, + ), + migrations.AddField( + model_name="breach", + name="sanctions_regimes", + field=models.ManyToManyField( + through="report_a_breach.SanctionsRegimeBreachThrough", + to="report_a_breach.sanctionsregime", + ), + ), + ] diff --git a/report_a_breach/migrations/0003_remove_breach_sanctions_regimes.py b/report_a_breach/migrations/0003_remove_breach_sanctions_regimes.py new file mode 100644 index 00000000..138d07af --- /dev/null +++ b/report_a_breach/migrations/0003_remove_breach_sanctions_regimes.py @@ -0,0 +1,16 @@ +# Generated by Django 4.2.9 on 2024-01-29 09:16 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("report_a_breach", "0002_breach_personorcompany_sanctionsregime_and_more"), + ] + + operations = [ + migrations.RemoveField( + model_name="breach", + name="sanctions_regimes", + ), + ] diff --git a/report_a_breach/migrations/0004_breach_sanctions_regimes.py b/report_a_breach/migrations/0004_breach_sanctions_regimes.py new file mode 100644 index 00000000..c828ada9 --- /dev/null +++ b/report_a_breach/migrations/0004_breach_sanctions_regimes.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.9 on 2024-01-31 11:31 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("report_a_breach", "0003_remove_breach_sanctions_regimes"), + ] + + operations = [ + migrations.AddField( + model_name="breach", + name="sanctions_regimes", + field=models.ManyToManyField( + through="report_a_breach.SanctionsRegimeBreachThrough", + to="report_a_breach.sanctionsregime", + ), + ), + ] diff --git a/report_a_breach/migrations/0005_merge_20240206_1556.py b/report_a_breach/migrations/0005_merge_20240206_1556.py new file mode 100644 index 00000000..ee4a8dff --- /dev/null +++ b/report_a_breach/migrations/0005_merge_20240206_1556.py @@ -0,0 +1,12 @@ +# Generated by Django 4.2.10 on 2024-02-06 15:56 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("report_a_breach", "0002_historicaluploadeddocument_and_more"), + ("report_a_breach", "0004_breach_sanctions_regimes"), + ] + + operations = [] diff --git a/report_a_breach/sanctions_regimes.json b/report_a_breach/sanctions_regimes.json new file mode 100644 index 00000000..c3c0ffc5 --- /dev/null +++ b/report_a_breach/sanctions_regimes.json @@ -0,0 +1,10 @@ +{ + "SanctionsRegimes": { + "The Afghanistan": "The Afghanistan (Sanctions) (EU Exit) Regulations 2020", + "The Republic of Belarus": "The Republic of Belarus (Sanctions) (EU Exit) Regulations 2019", + "The Burma": "The Burma (Sanctions) (EU Exit) Regulations 2019", + "The Democratic People’s Republic of Korea": "The Democratic People’s Republic of Korea (Sanctions) (EU Exit) Regulations 2019", + "The Iran" : "The Iran Human Rights (Sanctions) (EU Exit) Regulations 2019", + "The Russia": "The Russia (Sanctions) (EU Exit) Regulations 2019" + } +} diff --git a/report_a_breach/templates/confirmation.html b/report_a_breach/templates/confirmation.html index 711b7c03..02d05a19 100644 --- a/report_a_breach/templates/confirmation.html +++ b/report_a_breach/templates/confirmation.html @@ -1,11 +1,9 @@ {% extends "base.html" %} -{% load crispy_forms_tags crispy_forms_gds %} - {% block header__service %}
{% block header__service__name %} - Report a suspected breach of trade sanctions + Report a suspected breach of trade sanctions {% endblock %} {% block header__service__navigaton %} @@ -14,33 +12,33 @@ {% endblock %} {% block content %} -
-
-
-
-
-

- Submission complete -

-
- Your reference number
{{ application_reference_number }} +
+
+
+
+
+

+ Submission complete +

+
+ Your reference number
{{ application_reference_number }} +
-
-

We have sent you a confirmation email.

-

What happens next

-

- We’ve sent your report to the Department for Business and Trade. -

-

- They may contact you to ask for more information. -

-

+

We have sent you a confirmation email.

+

What happens next

+

+ We’ve sent your report to the Department for Business and Trade. +

+

+ They may contact you to ask for more information. +

+

- What did you think of this service? (takes 30 seconds) -

+ What did you think of this service? (takes 30 seconds) +

+
-
-
-
+ +
{% endblock %} diff --git a/report_a_breach/templates/summary.html b/report_a_breach/templates/summary.html index 030c8054..34b865a2 100644 --- a/report_a_breach/templates/summary.html +++ b/report_a_breach/templates/summary.html @@ -1,57 +1,65 @@ {% extends "base.html" %} +{% load crispy_forms_tags crispy_forms_gds %} {% load get_wizard_step_url %} {% block column_content %} -
- {{ wizard.management_form }} - {% csrf_token %} -
-

- Check your answers before submitting -

-
-
-
-

Your details

-
-
-
-
-
- Email -
-
- {{ reporter_email_address }} -
-
- Change email (Your details) -
-
-
-
- Full name -
-
- {{ reporter_full_name }} -
-
- Change full name (Your details) -
-
-
-
- What is the professional relationship with the company or person suspected of breaching - trade sanctions? -
-
- {{ reporter_professional_relationship }} -
-
- Change professional relationship with the organisation (Your details) -
-
-
-
-
- -
+
+
+

+ Check your answers before submitting +

+
+
+
+

Your details

+
+
+
+
+
+ Email +
+
+ {{ reporter_email_address }} +
+
+ Change email (Your details) +
+
+
+
+ Full name +
+
+ {{ reporter_full_name }} +
+
+ Change full name (Your details) +
+
+
+
+ What is the professional relationship with the company or person suspected of breaching + trade sanctions? +
+
+ {{ company_relationship }} +
+
+ Change professional relationship with the organisation (Your details) +
+
+
+
+
+ {{ wizard.management_form }} + {% if wizard.form.forms %} + {{ wizard.form.management_form }} + {% for form in wizard.form.forms %} + {% crispy form %} + {% endfor %} + {% else %} + {% crispy wizard.form %} + {% endif %} + +
{% endblock column_content %}