Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion features/date_of_birth_page.feature
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Feature: Date of birth page

Scenario: Checking responses and changing them
Given I am logged in
And I have answered have you ever smoked with an eligible response
And I have answered questions showing I am eligible
When I go to "/date-of-birth"
And I fill in and submit my date of birth as 55 years ago
When I go to "/check-your-answers"
Expand Down
1 change: 1 addition & 0 deletions features/have_you_ever_smoked_page.feature
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Feature: Have you ever smoked page

Scenario: Checking responses and changing them
Given I am logged in
And I have answered questions showing I am eligible
When I go to "/have-you-ever-smoked"
And I fill in and submit my smoking status with "Yes, I used to smoke"
When I go to "/check-your-answers"
Expand Down
2 changes: 1 addition & 1 deletion features/periods_when_you_stopped_smoking.feature
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Feature: Periods when you stopped smoking page
When I check "Yes"
And I fill in "Enter the total number of years you stopped smoking for" with "1"
And I submit the form
Then I am on "/check-your-answers"
Then I am on "/types-tobacco-smoking"

Scenario: Checking responses and changing them
Given I am logged in
Expand Down
7 changes: 5 additions & 2 deletions features/questionnaire.feature
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,12 @@ Feature: Questionnaire
And I fill in "Enter the total number of years you stopped smoking for" with "10"
And I submit the form

Then I am on "/check-your-answers"
And I see a back link to "/periods-when-you-stopped-smoking"
Then I am on "/types-tobacco-smoking"
When I check "Cigarettes"
And I check "Pipe"
And I submit the form

Then I am on "/check-your-answers"
And I see "Yes, I used to smoke" as a response to "Have you ever smoked tobacco?" under "Eligibility"
And I see a date 55 years ago as a response to "Date of birth" under "Eligibility"

Expand Down
20 changes: 20 additions & 0 deletions features/steps/debug_steps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from behave import when
from datetime import datetime

@given("I take a screenshot")
@given("I take a screenshot {value}")
@when("I take a screenshot")
@when("I take a screenshot {value}")
@then("I take a screenshot")
@then("I take a screenshot {value}")
def screenshot(context, value=""):
context.page.screenshot(
full_page=True, path=f"screenshots/{datetime.now()}-{value}-screenshot.png"
)

@given("I print eligibiity")
@when("I print eligibiity")
@then("I print eligibiity")
def print_eligibiity(context):
print("Is user eligible?: ", context.current_user.responseset_set.last().is_eligible())

5 changes: 0 additions & 5 deletions features/steps/form_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@ def when_i_enter_value_and_submit(context, field, value):
context.page.get_by_label(field).fill(value)
when_i_submit_the_form(context)

@when("I take a screenshot")
@when("I take a screenshot {value}")
def screenshot(context, value=""):
context.page.screenshot(full_page=True, path=f"screenshots/{datetime.now()}-{value}-screenshot.png")

@when('I fill in and submit my smoking status with "{smoking_status}"')
def when_i_fill_in_and_submit_my_smoking_status(context, smoking_status):
context.page.get_by_label(smoking_status).check()
Expand Down
45 changes: 45 additions & 0 deletions features/types_tobacco_smoking.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
@TypesTobaccoSmoking
Feature: Types tobacco smoking page
Scenario: The page is accessible
Given I am logged in
And I have answered questions showing I am eligible
When I go to "/types-tobacco-smoking"
Then there are no accessibility violations

Scenario: Form errors
Given I am logged in
And I have answered questions showing I am eligible
When I go to "/types-tobacco-smoking"
And I click "Continue"
Then I am on "/types-tobacco-smoking"
And I see a form error "Select the type of tobacco you smoke or have smoked"
And there are no accessibility violations

Scenario: Navigating backwards and forwards
Given I am logged in
And I have answered questions showing I am eligible
When I go to "/types-tobacco-smoking"
Then I see a back link to "/periods-when-you-stopped-smoking"
When I check "Cigarettes"
And I submit the form
Then I am on "/check-your-answers"

Scenario: Checking responses and changing them
Given I am logged in
And I have answered questions showing I am eligible
When I go to "/types-tobacco-smoking"
And I check "Cigarettes"
And I check "Cigars"
And I submit the form
When I go to "/check-your-answers"
Then I take a screenshot
Then I see "Cigarettes and Cigars" as a response to "Types of tobacco smoked" under "Smoking history"
And I see "/types-tobacco-smoking?change=True" as a link to change "Types of tobacco smoked" under "Smoking history"
When I click the link to change "Types of tobacco smoked" under "Smoking history"
Then I am on "/types-tobacco-smoking?change=True"
And I see "Cigarettes" selected
And I see "Cigars" selected
When I check "Pipe"
And I click "Continue"
Then I am on "/check-your-answers"
And I see "Cigarettes, Pipe, and Cigars" as a response to "Types of tobacco smoked" under "Smoking history"
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from django import forms

from ...nhsuk_forms.choice_field import MultipleChoiceField
from ..models.tobacco_smoking_history import TobaccoSmokingHistoryTypes, TobaccoSmokingHistory



class TypesTobaccoSmokingForm(forms.Form):

value = MultipleChoiceField(
choices=TobaccoSmokingHistoryTypes.choices,
widget=forms.CheckboxSelectMultiple,
label="What do you or have you smoked?",
label_classes="nhsuk-fieldset__legend--m",
hint="Select all that apply",
error_messages={
"required": "Select the type of tobacco you smoke or have smoked"
},
)

def __init__(self, *args, response_set, **kwargs):
super().__init__(*args, **kwargs)
self.response_set = response_set
self.existing_types = list(
response_set.tobacco_smoking_history.values_list('type', flat=True)
)
self.fields["value"].initial = self.existing_types

value_field=self['value']
value_field.add_hint_for_choice(
TobaccoSmokingHistoryTypes.CIGARILLOS,
"Cafe Creme or Signature cigars, roughly the size of a cigarette"
)


def save(self, commit=True):
if not self.is_valid():
return None

self._delete_types_not_selected()
return self._create_types_selected()


def _delete_types_not_selected(self):
for kind in self.existing_types:
if kind not in self.cleaned_data["value"]:
TobaccoSmokingHistory.objects.filter(response_set=self.response_set, type=kind).delete()


def _create_types_selected(self):
instances = [
TobaccoSmokingHistory(response_set=self.response_set, type=kind)
for kind in self.cleaned_data["value"]
if kind not in self.existing_types
]

TobaccoSmokingHistory.objects.bulk_create(instances)

return instances
2 changes: 1 addition & 1 deletion lung_cancer_screening/questions/jinja2/responses.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
</section>

<section>
<h2 class="nhsuk-heading-m">Smoking history</h2>
<h2 class="nhsuk-heading-m">Smoking history</h2>

{{ summaryList({
"rows": response_set.smoking_history_responses_items()
Expand Down
11 changes: 11 additions & 0 deletions lung_cancer_screening/questions/jinja2/types_tobacco_smoking.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{% extends 'question_form.jinja' %}

{% block prelude %}
<h1 class="nhsuk-heading-l">The type of tobacco you smoke or used to smoke</h1>

<p>Smoking affects your health in different ways depending on what you smoke.</p>

<p>We need to know what you smoke, or used to smoke, on a regular basis. For example, if you have smoked a pipe on a weekly basis for a year or longer.</p>

<p>You do not need to tell us about less frequent forms of smoking. For example, a cigar on special occasions.</p>
{% endblock prelude %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Generated by Django 5.2.10 on 2026-01-21 16:57

import django.contrib.postgres.fields
import django.db.models.deletion
import lung_cancer_screening.questions.models.validators.singleton_option
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("questions", "0045_periodswhenyoustoppedsmokingresponse_duration_years"),
]

operations = [
migrations.CreateModel(
name='TypesTobaccoSmokingResponse',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('value', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(choices=[('C', 'Cigarettes'), ('G', 'Cigars'), ('P', 'Pipes'), ('E', 'E-cigarettes or vaping'), ('N', 'None of the above')], max_length=1), size=None, validators=[lung_cancer_screening.questions.models.validators.singleton_option.validate_singleton_option])),
('response_set', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='types_tobacco_smoking_response', to='questions.responseset')),
],
options={
'abstract': False,
},
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Generated by Django 5.2.10 on 2026-01-27 14:59

import django.contrib.postgres.fields
import django.core.validators
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('questions', '0046_alter_ethnicityresponse_value_and_more'),
]

operations = [
migrations.AlterField(
model_name='agewhenstartedsmokingresponse',
name='value',
field=models.PositiveIntegerField(validators=[django.core.validators.MinValueValidator(1, message='The age you started smoking must be between 1 and your current age')]),
),
migrations.AlterField(
model_name='ethnicityresponse',
name='value',
field=models.CharField(choices=[('A', 'Asian or Asian British'), ('B', 'Black, African, Caribbean or Black British'), ('M', 'Mixed or multiple ethnic groups'), ('W', 'White'), ('O', 'Other ethnic group'), ('N', 'Prefer not to say')], max_length=1),
),
migrations.AlterField(
model_name='sexatbirthresponse',
name='value',
field=models.CharField(choices=[('F', 'Female'), ('M', 'Male'), ('I', 'Intersex')], max_length=1),
),
migrations.AlterField(
model_name='typestobaccosmokingresponse',
name='value',
field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(choices=[('C', 'Cigarettes'), ('R', 'Rolled cigarettes, or roll-ups'), ('P', 'Pipe'), ('G', 'Cigars'), ('E', 'Cigarillos'), ('S', 'Shisha')], max_length=1), size=None),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Generated by Django 5.2.10 on 2026-01-28 10:46

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('questions', '0047_alter_agewhenstartedsmokingresponse_value_and_more'),
]

operations = [
migrations.CreateModel(
name='TobaccoSmokingHistory',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('type', models.CharField(choices=[('Cigarettes', 'Cigarettes'), ('RolledCigarettes', 'Rolled cigarettes, or roll-ups'), ('Pipe', 'Pipe'), ('Cigars', 'Cigars'), ('Cigarillos', 'Cigarillos'), ('Shisha', 'Shisha')])),
('response_set', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='types_tobacco_smoking', to='questions.responseset')),
],
options={
'abstract': False,
},
),
migrations.DeleteModel(
name='TypesTobaccoSmokingResponse',
),
]
1 change: 1 addition & 0 deletions lung_cancer_screening/questions/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@
from .relatives_age_when_diagnosed_response import RelativesAgeWhenDiagnosedResponse # noqa: F401
from .respiratory_conditions_response import RespiratoryConditionsResponse # noqa: F401
from .sex_at_birth_response import SexAtBirthResponse # noqa: F401
from .tobacco_smoking_history import TobaccoSmokingHistory # noqa: F401
from .weight_response import WeightResponse # noqa: F401
33 changes: 33 additions & 0 deletions lung_cancer_screening/questions/models/tobacco_smoking_history.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from django.db import models

from .base import BaseModel
from .response_set import ResponseSet


class TobaccoSmokingHistoryTypes(models.TextChoices):
CIGARETTES = "Cigarettes", "Cigarettes"
ROLLED_CIGARETTES = "RolledCigarettes", "Rolled cigarettes, or roll-ups"
PIPE = "Pipe", "Pipe"
CIGARS = "Cigars", "Cigars"
CIGARILLOS = "Cigarillos", "Cigarillos"
SHISHA = "Shisha", "Shisha"


class TobaccoSmokingHistory(BaseModel):
response_set = models.ForeignKey(
ResponseSet,
on_delete=models.CASCADE,
related_name="tobacco_smoking_history",
)
type = models.CharField(
choices=TobaccoSmokingHistoryTypes.choices
)

class Meta:
constraints = [
models.UniqueConstraint(
fields=["response_set", "type"],
name="unique_tobacco_smoking_history_per_response_set",
violation_error_message="A tobacco smoking history already exists for this response set and type"
)
]
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from ..models.education_response import EducationValues
from ..models.respiratory_conditions_response import RespiratoryConditionValues
from ..models.family_history_lung_cancer_response import FamilyHistoryLungCancerValues
from ..models.tobacco_smoking_history import TobaccoSmokingHistoryTypes

class ResponseSetPresenter:
DATE_FORMAT = "%-d %B %Y" # eg 8 September 2000
Expand Down Expand Up @@ -147,8 +148,20 @@ def respiratory_conditions(self):
])


@property
def types_tobacco_smoking(self):
types_smoked = self.response_set.tobacco_smoking_history.values_list('type', flat=True)

types_smoked_ordered = sorted(types_smoked, key=lambda x: TobaccoSmokingHistoryTypes.values.index(x))

return self._list_to_sentence([
TobaccoSmokingHistoryTypes(code).label
for code in types_smoked_ordered
])


def eligibility_responses_items(self):
return [
items = [
self._check_your_answer_item(
"Have you ever smoked tobacco?",
self.have_you_ever_smoked,
Expand All @@ -158,9 +171,10 @@ def eligibility_responses_items(self):
"Date of birth",
self.date_of_birth,
"questions:date_of_birth",
)
),
]

return items

def about_you_responses_items(self):
return [
Expand Down Expand Up @@ -247,6 +261,11 @@ def smoking_history_responses_items(self):
self.periods_when_you_stopped_smoking,
"questions:periods_when_you_stopped_smoking",
),
self._check_your_answer_item(
"Types of tobacco smoked",
self.types_tobacco_smoking,
"questions:types_tobacco_smoking",
)
]


Expand Down
Loading