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

Feat: CalFresh help info #1970

Merged
merged 9 commits into from
Mar 22, 2024
7 changes: 6 additions & 1 deletion benefits/core/context_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@
from . import models, session


def unique_values(original_list):
# dict.fromkeys gets the unique values and preserves order
return list(dict.fromkeys(original_list))
thekaveman marked this conversation as resolved.
Show resolved Hide resolved


def _agency_context(agency):
return {
"eligibility_index_url": agency.eligibility_index_url,
"help_template": agency.help_template,
"help_templates": unique_values([v.help_template for v in agency.active_verifiers if v.help_template is not None]),
"info_url": agency.info_url,
"long_name": agency.long_name,
"phone": agency.phone,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 5.0.3 on 2024-03-21 00:31

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("core", "0004_alter_eligibilityverifier_display_order"),
]

operations = [
migrations.RemoveField(
model_name="transitagency",
name="help_template",
),
migrations.AddField(
model_name="eligibilityverifier",
name="help_template",
field=models.TextField(null=True),
),
]
12 changes: 6 additions & 6 deletions benefits/core/migrations/local_fixtures.json
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,8 @@
"auth_provider": null,
"selection_label_template": "eligibility/includes/selection-label--mst-courtesy-card.html",
"start_template": "eligibility/start--mst-courtesy-card.html",
"form_class": "benefits.eligibility.forms.MSTCourtesyCard"
"form_class": "benefits.eligibility.forms.MSTCourtesyCard",
"help_template": "core/includes/help--mst-courtesy-card.html"
}
},
{
Expand Down Expand Up @@ -249,7 +250,8 @@
"auth_provider": null,
"selection_label_template": "eligibility/includes/selection-label--sbmtd-mobility-pass.html",
"start_template": "eligibility/start--sbmtd-mobility-pass.html",
"form_class": "benefits.eligibility.forms.SBMTDMobilityPass"
"form_class": "benefits.eligibility.forms.SBMTDMobilityPass",
"help_template": "core/includes/help--sbmtd-mobility-pass.html"
}
},
{
Expand All @@ -270,7 +272,8 @@
"auth_provider": 1,
"selection_label_template": "eligibility/includes/selection-label--calfresh.html",
"start_template": "eligibility/start--calfresh.html",
"form_class": null
"form_class": null,
"help_template": "core/includes/help--calfresh.html"
}
},
{
Expand Down Expand Up @@ -334,7 +337,6 @@
"index_template": "core/index--mst.html",
"eligibility_index_template": "eligibility/index--mst.html",
"enrollment_success_template": "enrollment/success--mst.html",
"help_template": "core/includes/help--mst.html",
"eligibility_types": [1, 7, 2, 3],
"eligibility_verifiers": [1, 7, 2, 3]
}
Expand All @@ -358,7 +360,6 @@
"index_template": "core/index--sacrt.html",
"eligibility_index_template": "eligibility/index--sacrt.html",
"enrollment_success_template": "enrollment/success--sacrt.html",
"help_template": null,
"eligibility_types": [4],
"eligibility_verifiers": [4]
}
Expand All @@ -382,7 +383,6 @@
"index_template": "core/index--sbmtd.html",
"eligibility_index_template": "eligibility/index--sbmtd.html",
"enrollment_success_template": "enrollment/success--sbmtd.html",
"help_template": "core/includes/help--sbmtd.html",
"eligibility_types": [5, 6],
"eligibility_verifiers": [5, 6]
}
Expand Down
7 changes: 6 additions & 1 deletion benefits/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ class EligibilityVerifier(models.Model):
start_template = models.TextField(null=True)
# reference to a form class used by this Verifier, e.g. benefits.app.forms.FormClass
form_class = models.TextField(null=True)
help_template = models.TextField(null=True)

class Meta:
ordering = ["display_order"]
Expand Down Expand Up @@ -269,7 +270,6 @@ class TransitAgency(models.Model):
index_template = models.TextField()
eligibility_index_template = models.TextField()
enrollment_success_template = models.TextField()
help_template = models.TextField(null=True)

def __str__(self):
return self.long_name
Expand Down Expand Up @@ -323,6 +323,11 @@ def public_key_data(self):
"""This Agency's public key as a string."""
return self.public_key.data

@property
def active_verifiers(self):
"""This Agency's eligibility verifiers that are active."""
return self.eligibility_verifiers.filter(active=True)

@staticmethod
def by_id(id):
"""Get a TransitAgency instance by its ID."""
Expand Down
6 changes: 4 additions & 2 deletions benefits/core/templates/core/help.html
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,10 @@ <h2 class="h2-sm pt-4 pt-lg-8" id="login-gov-verify">{% translate "How do I veri
{% endblocktranslate %}
</p>

{% if agency and agency.help_template %}
{% include agency.help_template %}
{% if agency and agency.help_templates %}
{% for help_template in agency.help_templates %}
{% include help_template %}
{% endfor %}
{% endif %}

<h2 class="h2-sm pt-4 pt-lg-8" id="littlepay">{% translate "What is Littlepay?" %}</h2>
Expand Down
41 changes: 41 additions & 0 deletions benefits/core/templates/core/includes/help--calfresh.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{% load i18n %}

<h2 class="h2-sm pt-4 pt-lg-8" id="calfresh-transit-benefit">
{% translate "How do I know if I'm eligible for the transit benefit for CalFresh Cardholders?" %}
</h2>
<p class="pt-2 pt-lg-4">
{% blocktranslate trimmed %}
We verify your eligibility as a CalFresh Cardholder by confirming you have received funds in your
CalFresh account at any point in the last three months. This means you are eligible for a transit
benefit even if you did not receive funds in your CalFresh account this month or last month.
{% endblocktranslate %}
</p>

<h2 class="h2-sm pt-4 pt-lg-8" id="calfresh-transit-benefit-no-account-changes">
{% translate "Will this transit benefit change my CalFresh account?" %}
</h2>
<p class="pt-2 pt-lg-4">
{% blocktranslate trimmed %}
No. Your monthly CalFresh allotment will not change.
{% endblocktranslate %}
</p>

<h2 class="h2-sm pt-4 pt-lg-8" id="calfresh-transit-benefit-enrollment">
{% translate "Do I need my Golden State Advantage card to enroll?" %}
</h2>
<p class="pt-2 pt-lg-4">
{% blocktranslate trimmed %}
No, you do not need your physical EBT card to enroll. We use information from Login.gov and the California
Department of Social Services to enroll you in the benefit.
{% endblocktranslate %}
</p>

<h2 class="h2-sm pt-4 pt-lg-8" id="calfresh-transit-benefit-payment">
{% translate "Can I use my Golden State Advantage card to pay for transit rides?" %}
</h2>
<p class="pt-2 pt-lg-4">
{% blocktranslate trimmed %}
No. You can not use your EBT or P-EBT card to pay for public transportation. When you tap to ride, use your personal
contactless debit or credit card to pay for public transportation.
{% endblocktranslate %}
</p>
2 changes: 1 addition & 1 deletion benefits/eligibility/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class EligibilityVerifierSelectionForm(forms.Form):

def __init__(self, agency: models.TransitAgency, *args, **kwargs):
super().__init__(*args, **kwargs)
verifiers = agency.eligibility_verifiers.filter(active=True)
verifiers = agency.active_verifiers

self.classes = "col-lg-8"
# second element is not used since we render the whole label using selection_label_template,
Expand Down
39 changes: 39 additions & 0 deletions tests/pytest/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,45 @@ def model_EligibilityType():
return eligibility


@pytest.fixture
def model_EligibilityType_does_not_support_expiration(model_EligibilityType):
model_EligibilityType.supports_expiration = False
model_EligibilityType.expiration_days = 0
model_EligibilityType.save()

return model_EligibilityType


@pytest.fixture
def model_EligibilityType_zero_expiration_days(model_EligibilityType):
model_EligibilityType.supports_expiration = True
model_EligibilityType.expiration_days = 0
model_EligibilityType.expiration_reenrollment_days = 14
model_EligibilityType.save()

return model_EligibilityType


@pytest.fixture
def model_EligibilityType_zero_expiration_reenrollment_days(model_EligibilityType):
model_EligibilityType.supports_expiration = True
model_EligibilityType.expiration_days = 14
model_EligibilityType.expiration_reenrollment_days = 0
model_EligibilityType.save()

return model_EligibilityType


@pytest.fixture
def model_EligibilityType_supports_expiration(model_EligibilityType):
model_EligibilityType.supports_expiration = True
model_EligibilityType.expiration_days = 365
model_EligibilityType.expiration_reenrollment_days = 14
model_EligibilityType.save()

return model_EligibilityType


@pytest.fixture
def model_EligibilityVerifier(model_PemData, model_EligibilityType):
verifier = EligibilityVerifier.objects.create(
Expand Down
9 changes: 9 additions & 0 deletions tests/pytest/core/test_context_processors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from benefits.core.context_processors import unique_values


def test_unique_values():
original_list = ["a", "b", "c", "a", "a", "zzz", "b", "c", "d", "b"]

new_list = unique_values(original_list)

assert new_list == ["a", "b", "c", "zzz", "d"]
56 changes: 17 additions & 39 deletions tests/pytest/core/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,45 +13,6 @@ def mock_requests_get_pem_data(mocker):
return mocker.patch("benefits.core.models.requests.get", return_value=mocker.Mock(text="PEM text"))


@pytest.fixture
def model_EligibilityType_does_not_support_expiration(model_EligibilityType):
model_EligibilityType.supports_expiration = False
model_EligibilityType.expiration_days = 0
model_EligibilityType.save()

return model_EligibilityType


@pytest.fixture
def model_EligibilityType_zero_expiration_days(model_EligibilityType):
model_EligibilityType.supports_expiration = True
model_EligibilityType.expiration_days = 0
model_EligibilityType.expiration_reenrollment_days = 14
model_EligibilityType.save()

return model_EligibilityType


@pytest.fixture
def model_EligibilityType_zero_expiration_reenrollment_days(model_EligibilityType):
model_EligibilityType.supports_expiration = True
model_EligibilityType.expiration_days = 14
model_EligibilityType.expiration_reenrollment_days = 0
model_EligibilityType.save()

return model_EligibilityType


@pytest.fixture
def model_EligibilityType_supports_expiration(model_EligibilityType):
model_EligibilityType.supports_expiration = True
model_EligibilityType.expiration_days = 365
model_EligibilityType.expiration_reenrollment_days = 14
model_EligibilityType.save()

return model_EligibilityType


def test_SecretNameField_init():
field = SecretNameField()

Expand Down Expand Up @@ -356,6 +317,23 @@ def test_TransitAgency_str(model_TransitAgency):
assert str(model_TransitAgency) == model_TransitAgency.long_name


@pytest.mark.django_db
def test_TransitAgency_active_verifiers(model_TransitAgency, model_EligibilityVerifier):
# add another to the list of verifiers by cloning the original
# https://stackoverflow.com/a/48149675/453168
new_verifier = EligibilityVerifier.objects.get(pk=model_EligibilityVerifier.id)
new_verifier.pk = None
new_verifier.active = False
new_verifier.save()

model_TransitAgency.eligibility_verifiers.add(new_verifier)

assert model_TransitAgency.eligibility_verifiers.count() == 2
assert model_TransitAgency.active_verifiers.count() == 1

assert model_TransitAgency.active_verifiers[0] == model_EligibilityVerifier


@pytest.mark.django_db
def test_TransitAgency_get_type_id_matching(model_TransitAgency):
eligibility = model_TransitAgency.eligibility_types.first()
Expand Down
5 changes: 5 additions & 0 deletions tests/pytest/core/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ def session_reset_spy(mocker):
@pytest.fixture
def mocked_active_agency(mocker):
mock_agency = mocker.Mock()

# ensure agency.eligibility_verifiers is iterable
eligibility_verifiers = mocker.MagicMock()
mock_agency.active_verifiers = eligibility_verifiers

mock_agency.index_url = "/agency"
mocker.patch("benefits.core.session.agency", return_value=mock_agency)
mocker.patch("benefits.core.session.active_agency", return_value=True)
Expand Down
14 changes: 10 additions & 4 deletions tests/pytest/eligibility/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,12 @@ def test_index_get_agency_multiple_verifiers(
):
# override the mocked session agency with a mock agency that has multiple verifiers
mock_agency = mocker.Mock(spec=model_TransitAgency)
mock_agency.eligibility_verifiers.filter.return_value = [model_EligibilityVerifier, model_EligibilityVerifier]
mock_agency.eligibility_verifiers.count.return_value = 2

# mock the active_verifiers property on the class - https://stackoverflow.com/a/55642462
type(mock_agency).active_verifiers = mocker.PropertyMock(
thekaveman marked this conversation as resolved.
Show resolved Hide resolved
return_value=[model_EligibilityVerifier, model_EligibilityVerifier]
)

mock_agency.index_url = "/agency"
mock_agency.eligibility_index_template = "eligibility/index.html"
mocked_session_agency.return_value = mock_agency
Expand All @@ -107,8 +111,10 @@ def test_index_get_agency_single_verifier(
):
# override the mocked session agency with a mock agency that has a single verifier
mock_agency = mocker.Mock(spec=model_TransitAgency)
mock_agency.eligibility_verifiers.filter.return_value = [model_EligibilityVerifier]
mock_agency.eligibility_verifiers.count.return_value = 1

# mock the active_verifiers property on the class - https://stackoverflow.com/a/55642462
type(mock_agency).active_verifiers = mocker.PropertyMock(return_value=[model_EligibilityVerifier])

mock_agency.index_url = "/agency"
mock_agency.eligibility_index_template = "eligibility/index.html"
mocked_session_agency.return_value = mock_agency
Expand Down
Loading