Skip to content

Commit

Permalink
Merge pull request #1248 from ministryofjustice/feature/LGA-3007-Call…
Browse files Browse the repository at this point in the history
…back-capping-third-party

LGA 3007: Callback capping third party
  • Loading branch information
BenMillar-CGI committed Apr 10, 2024
2 parents 6d5ef44 + 9440c08 commit 1899695
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 14 deletions.
33 changes: 33 additions & 0 deletions cla_public/apps/contact/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,34 @@ def scheduled_time(self, today=None):
return None


class ThirdPartyAvailabilityCheckerForm(AvailabilityCheckerForm):
time_today = TimeChoiceField(
choices_callback=OPERATOR_HOURS.today_slots,
third_party_callback=True,
validators=[
IgnoreIf("specific_day", FieldValueNot(DAY_TODAY)),
InputRequired(message=_(TIME_TODAY_VALIDATION_ERROR)),
AvailableSlot(DAY_TODAY),
],
)
day = DayChoiceField(
third_party_callback=True,
validators=[
IgnoreIf("specific_day", FieldValueNot(DAY_SPECIFIC)),
InputRequired(message=_(DAY_SPECIFIC_VALIDATION_ERROR)),
],
)
time_in_day = TimeChoiceField(
choices_callback=OPERATOR_HOURS.time_slots,
third_party_callback=True,
validators=[
IgnoreIf("specific_day", FieldValueNot(DAY_SPECIFIC)),
InputRequired(message=_(TIME_SPECIFIC_VALIDATION_ERROR)),
AvailableSlot(DAY_SPECIFIC),
],
)


class AvailabilityCheckerField(FormField):
"""Convenience class for FormField(AvailabilityCheckerForm"""

Expand All @@ -247,6 +275,11 @@ def scheduled_time(self):
return self.form.scheduled_time()


class ThirdPartyAvailabilityCheckerField(AvailabilityCheckerField):
def __init__(self, *args, **kwargs):
super(AvailabilityCheckerField, self).__init__(ThirdPartyAvailabilityCheckerForm, *args, **kwargs)


class ValidatedFormField(FormField):
def __init__(self, form_class, *args, **kwargs):
self._errors = []
Expand Down
8 changes: 6 additions & 2 deletions cla_public/apps/contact/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
from wtforms.validators import InputRequired, Optional, Required, Length

from cla_common.constants import ADAPTATION_LANGUAGES, THIRDPARTY_RELATIONSHIP, CALLBACK_TYPES
from cla_public.apps.contact.fields import AvailabilityCheckerField, ValidatedFormField
from cla_public.apps.contact.fields import (
AvailabilityCheckerField,
ValidatedFormField,
ThirdPartyAvailabilityCheckerField,
)
from cla_public.apps.checker.constants import (
SAFE_TO_CONTACT,
CONTACT_PREFERENCE,
Expand Down Expand Up @@ -107,7 +111,7 @@ class ThirdPartyForm(BabelTranslationsFormMixin, NoCsrfForm):
Length(max=20, message=_(u"Your telephone number must be 20 characters or less")),
],
)
time = AvailabilityCheckerField(label=_(u"Select a time for us to call"))
time = ThirdPartyAvailabilityCheckerField(label=_(u"Select a time for us to call"))


class AddressForm(BabelTranslationsFormMixin, NoCsrfForm):
Expand Down
87 changes: 76 additions & 11 deletions cla_public/apps/contact/tests/test_fields.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,91 @@
from unittest import TestCase
from flask import current_app
from mock import patch
from mock import patch, Mock
from cla_public.apps.contact.fields import (
AvailabilityCheckerForm,
ThirdPartyAvailabilityCheckerForm,
time_slots_for_day,
)
import datetime


class TestFeatureFlag(TestCase):
@patch("cla_public.apps.contact.api.get_valid_callback_timeslots_on_date")
@patch("cla_common.call_centre_availability.OpeningHours.time_slots")
@patch("cla_public.apps.contact.fields.time_slots_for_day")
def test_feature_flag_enabled(self, cla_backend_slots, cla_common_slots, get_timeslots):
@patch("cla_public.apps.contact.fields.get_valid_callback_timeslots_on_date")
@patch("cla_public.apps.contact.fields.OpeningHours.time_slots")
def test_feature_flag_enabled(self, cla_backend_slots, cla_common_slots):
current_app.config["USE_BACKEND_CALLBACK_SLOTS"] = True
date = datetime.date(2024, 1, 1)
get_timeslots(date)
time_slots_for_day(date)
cla_backend_slots.assert_called()
cla_common_slots.assert_not_called()

@patch("cla_public.apps.contact.api.get_valid_callback_timeslots_on_date")
@patch("cla_common.call_centre_availability.OpeningHours.time_slots")
@patch("cla_public.apps.contact.fields.time_slots_for_day")
def test_feature_flag_disabled(self, cla_backend_slots, cla_common_slots, get_timeslots):
@patch("cla_public.apps.contact.fields.get_valid_callback_timeslots_on_date")
@patch("cla_public.apps.contact.fields.OpeningHours.time_slots")
def test_feature_flag_disabled(self, cla_backend_slots, cla_common_slots):
current_app.config["USE_BACKEND_CALLBACK_SLOTS"] = False
date = datetime.date(2024, 1, 1)
get_timeslots(date)
time_slots_for_day(date)
cla_backend_slots.assert_not_called()
cla_common_slots.assert_called()


class TestCallbackForm(TestCase):
@patch("cla_public.apps.contact.api.get_valid_callback_slots", Mock(return_value=[]))
def test_field_attribute_set(self):
form = AvailabilityCheckerForm()
assert form.time_in_day.is_third_party_callback is False
assert form.time_today.is_third_party_callback is False

@patch("cla_public.apps.contact.fields.get_valid_callback_timeslots_on_date")
@patch.dict(current_app.config, {"USE_BACKEND_CALLBACK_SLOTS": True})
@patch("cla_public.apps.contact.api.get_valid_callback_slots", Mock(return_value=[]))
def test_time_field_choices(self, get_timeslots):
AvailabilityCheckerForm()
get_timeslots.assert_called_with(datetime.date.today(), is_third_party_callback=False)

@patch("cla_public.apps.contact.fields.time_slots_for_day")
@patch.dict(current_app.config, {"USE_BACKEND_CALLBACK_SLOTS": True})
@patch("cla_public.apps.contact.api.get_valid_callback_slots", Mock(return_value=[]))
def test_time_field_day_change(self, get_timeslots):
new_date = datetime.date(2024, 1, 1)
form = AvailabilityCheckerForm()
form.time_in_day.set_day_choices(new_date)
get_timeslots.assert_called_with(new_date, False)

@patch("cla_public.apps.contact.fields.get_valid_callback_days")
@patch.dict(current_app.config, {"USE_BACKEND_CALLBACK_SLOTS": True})
@patch("cla_public.apps.contact.api.get_valid_callback_slots", Mock(return_value=[]))
def test_day_field_choices(self, get_valid_callback_days):
AvailabilityCheckerForm()
get_valid_callback_days.assert_called_with(include_today=False, is_third_party_callback=False)


class TestThirdPartyForm(TestCase):
@patch("cla_public.apps.contact.api.get_valid_callback_slots", Mock(return_value=[]))
def test_field_attribute_set(self):
form = ThirdPartyAvailabilityCheckerForm()
assert form.time_in_day.is_third_party_callback is True
assert form.time_today.is_third_party_callback is True

@patch("cla_public.apps.contact.fields.get_valid_callback_timeslots_on_date")
@patch.dict(current_app.config, {"USE_BACKEND_CALLBACK_SLOTS": True})
@patch("cla_public.apps.contact.api.get_valid_callback_slots", Mock(return_value=[]))
def test_time_field_choices(self, get_timeslots):
ThirdPartyAvailabilityCheckerForm()
get_timeslots.assert_called_with(datetime.date.today(), is_third_party_callback=True)

@patch("cla_public.apps.contact.fields.time_slots_for_day")
@patch.dict(current_app.config, {"USE_BACKEND_CALLBACK_SLOTS": True})
@patch("cla_public.apps.contact.api.get_valid_callback_slots", Mock(return_value=[]))
def test_time_field_day_change(self, get_timeslots):
new_date = datetime.date(2024, 1, 1)
form = ThirdPartyAvailabilityCheckerForm()
form.time_in_day.set_day_choices(new_date)
get_timeslots.assert_called_with(new_date, True)

@patch("cla_public.apps.contact.fields.get_valid_callback_days")
@patch.dict(current_app.config, {"USE_BACKEND_CALLBACK_SLOTS": True})
@patch("cla_public.apps.contact.api.get_valid_callback_slots", Mock(return_value=[]))
def test_day_field_choices(self, get_valid_callback_days):
ThirdPartyAvailabilityCheckerForm()
get_valid_callback_days.assert_called_with(include_today=False, is_third_party_callback=True)
2 changes: 1 addition & 1 deletion helm_deploy/cla-public/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,4 @@ envVars:
USE_BACKEND_CALLBACK_SLOTS:
configmap:
name: backend-callback-slots
key: enabled
key: enabled

0 comments on commit 1899695

Please sign in to comment.