diff --git a/benefits/core/admin.py b/benefits/core/admin.py index cb468b629..6a06fee20 100644 --- a/benefits/core/admin.py +++ b/benefits/core/admin.py @@ -5,6 +5,7 @@ import logging import requests +from adminsortable2.admin import SortableAdminMixin from django.conf import settings from django.contrib import admin from . import models @@ -17,7 +18,6 @@ for model in [ models.EligibilityType, - models.EligibilityVerifier, models.PaymentProcessor, models.PemData, models.TransitAgency, @@ -26,6 +26,11 @@ admin.site.register(model) +@admin.register(models.EligibilityVerifier) +class SortableEligibilityVerifierAdmin(SortableAdminMixin, admin.ModelAdmin): + pass + + def pre_login_user(user, request): logger.debug(f"Running pre-login callback for user: {user.username}") token = request.session.get("google_sso_access_token") diff --git a/benefits/core/migrations/0004_alter_eligibilityverifier_display_order.py b/benefits/core/migrations/0004_alter_eligibilityverifier_display_order.py new file mode 100644 index 000000000..f455e8e24 --- /dev/null +++ b/benefits/core/migrations/0004_alter_eligibilityverifier_display_order.py @@ -0,0 +1,30 @@ +# Generated by Django 5.0.3 on 2024-03-19 20:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("core", "0003_eligibilitytype_expiration"), + ] + + # see https://django-admin-sortable2.readthedocs.io/en/latest/usage.html#initial-data + def set_initial_display_order(apps, schema_editor): + EligibilityVerifier = apps.get_model("core", "EligibilityVerifier") + for order, item in enumerate(EligibilityVerifier.objects.all(), 1): + item.display_order = order + item.save(update_fields=["display_order"]) + + operations = [ + migrations.AlterModelOptions( + name="eligibilityverifier", + options={"ordering": ["display_order"]}, + ), + migrations.AddField( + model_name="eligibilityverifier", + name="display_order", + field=models.PositiveSmallIntegerField(default=0), + ), + migrations.RunPython(set_initial_display_order, reverse_code=migrations.RunPython.noop), + ] diff --git a/benefits/core/migrations/local_fixtures.json b/benefits/core/migrations/local_fixtures.json index 1e51dad7a..0dc81799b 100644 --- a/benefits/core/migrations/local_fixtures.json +++ b/benefits/core/migrations/local_fixtures.json @@ -117,11 +117,21 @@ "group_id": "group123" } }, + { + "model": "core.eligibilitytype", + "pk": 7, + "fields": { + "name": "calfresh", + "label": "CalFresh", + "group_id": "group123" + } + }, { "model": "core.eligibilityverifier", "pk": 1, "fields": { "name": "(MST) oauth claims via Login.gov", + "display_order": 1, "active": true, "api_url": null, "api_auth_header": null, @@ -142,6 +152,7 @@ "pk": 2, "fields": { "name": "(MST) VA.gov - veteran", + "display_order": 3, "active": true, "api_url": null, "api_auth_header": null, @@ -162,6 +173,7 @@ "pk": 3, "fields": { "name": "(MST) eligibility server verifier", + "display_order": 4, "active": true, "api_url": "http://server:8000/verify", "api_auth_header": "X-Server-API-Key", @@ -182,6 +194,7 @@ "pk": 4, "fields": { "name": "(SacRT) oauth claims via Login.gov", + "display_order": 5, "active": false, "api_url": null, "api_auth_header": null, @@ -202,6 +215,7 @@ "pk": 5, "fields": { "name": "(SBMTD) oauth claims via Login.gov", + "display_order": 6, "active": false, "api_url": null, "api_auth_header": null, @@ -222,6 +236,7 @@ "pk": 6, "fields": { "name": "(SBMTD) eligibility server verifier", + "display_order": 7, "active": true, "api_url": "http://server:8000/verify", "api_auth_header": "X-Server-API-Key", @@ -237,6 +252,27 @@ "form_class": "benefits.eligibility.forms.SBMTDMobilityPass" } }, + { + "model": "core.eligibilityverifier", + "pk": 7, + "fields": { + "name": "(MST) CalFresh oauth claims via Login.gov", + "display_order": 2, + "active": true, + "api_url": null, + "api_auth_header": null, + "api_auth_key_secret_name": null, + "eligibility_type": 7, + "public_key": null, + "jwe_cek_enc": null, + "jwe_encryption_alg": null, + "jws_signing_alg": null, + "auth_provider": 1, + "selection_label_template": "eligibility/includes/selection-label--calfresh.html", + "start_template": "", + "form_class": null + } + }, { "model": "core.paymentprocessor", "pk": 1, @@ -299,8 +335,8 @@ "eligibility_index_template": "eligibility/index--mst.html", "enrollment_success_template": "enrollment/success--mst.html", "help_template": "core/includes/help--mst.html", - "eligibility_types": [1, 2, 3], - "eligibility_verifiers": [1, 2, 3] + "eligibility_types": [1, 7, 2, 3], + "eligibility_verifiers": [1, 7, 2, 3] } }, { diff --git a/benefits/core/models.py b/benefits/core/models.py index ec3c3499b..36010414a 100644 --- a/benefits/core/models.py +++ b/benefits/core/models.py @@ -158,6 +158,7 @@ class EligibilityVerifier(models.Model): id = models.AutoField(primary_key=True) name = models.TextField() + display_order = models.PositiveSmallIntegerField(default=0, blank=False, null=False) active = models.BooleanField(default=False) api_url = models.TextField(null=True) api_auth_header = models.TextField(null=True) @@ -177,6 +178,9 @@ class EligibilityVerifier(models.Model): # reference to a form class used by this Verifier, e.g. benefits.app.forms.FormClass form_class = models.TextField(null=True) + class Meta: + ordering = ["display_order"] + def __str__(self): return self.name diff --git a/benefits/eligibility/templates/eligibility/includes/modal--calfresh.html b/benefits/eligibility/templates/eligibility/includes/modal--calfresh.html new file mode 100644 index 000000000..3098b39ac --- /dev/null +++ b/benefits/eligibility/templates/eligibility/includes/modal--calfresh.html @@ -0,0 +1,42 @@ +{% extends "core/includes/modal.html" %} +{% load i18n %} +{% load static %} + +{% block modal-content %} +

{% translate "Learn more about the transit benefit for CalFresh Cardholders" %}

+
+

{% translate "How do I know if I'm eligible for the transit benefit for CalFresh Cardholders?" %}

+

+ {% 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 %} +

+ +

{% translate "Will this transit benefit change my CalFresh account?" %}

+

+ {% blocktranslate trimmed %} + No. Your monthly CalFresh allotment will not change. + {% endblocktranslate %} +

+

{% translate "Do I need my Golden State Advantage card to enroll?" %}

+

+ {% 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 %} +

+

{% translate "Can I use my Golden State Advantage card to pay for transit rides?" %}

+

+ {% 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 %} +

+ +

+ {% translate "Go back" %} +

+
+{% endblock modal-content %} diff --git a/benefits/eligibility/templates/eligibility/includes/selection-label--calfresh.html b/benefits/eligibility/templates/eligibility/includes/selection-label--calfresh.html new file mode 100644 index 000000000..e44fe3376 --- /dev/null +++ b/benefits/eligibility/templates/eligibility/includes/selection-label--calfresh.html @@ -0,0 +1,18 @@ +{% extends "eligibility/includes/selection-label.html" %} +{% load i18n %} + +{% block label %} + {% translate "CalFresh Cardholder" %} +{% endblock label %} + +{% block description %} + {% translate "You must have" %} + {% translate "recently received CalFresh funds" as calfresh_modal_link %} + {% include "core/includes/modal-trigger.html" with modal="modal--calfresh" text=calfresh_modal_link period=True %} + {% include "eligibility/includes/modal--calfresh.html" with id="modal--calfresh" size="modal-lg" header="p-md-2 p-3" body="pb-md-3 mb-md-3 mx-md-3 py-0 pt-0 absolute-top" %} + + {% translate "This transit benefit will remain active for one year. You will need to verify your identity with" %} + {% include "core/includes/modal-trigger.html" with classes="border-0 bg-transparent p-0 login" modal="modal--login-gov-veteran" login=True period=True %} + {% include "eligibility/includes/modal--login-gov-help.html" with id="modal--login-gov-calfresh" size="modal-lg" header="p-md-2 p-3" body="pb-md-3 mb-md-3 mx-md-3 py-0 pt-0 absolute-top" %} + +{% endblock description %} diff --git a/benefits/locale/en/LC_MESSAGES/django.po b/benefits/locale/en/LC_MESSAGES/django.po index 76ab9d419..cf2d22f61 100644 --- a/benefits/locale/en/LC_MESSAGES/django.po +++ b/benefits/locale/en/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Report-Msgid-Bugs-To: https://github.com/cal-itp/benefits/issues \n" -"POT-Creation-Date: 2024-03-13 22:40+0000\n" +"POT-Creation-Date: 2024-03-20 18:12+0000\n" "Language: English\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -368,6 +368,45 @@ msgstr "" msgid "A phone number with a phone plan associated with your name" msgstr "" +msgid "Learn more about the transit benefit for CalFresh Cardholders" +msgstr "" + +msgid "" +"How do I know if I'm eligible for the transit benefit for CalFresh " +"Cardholders?" +msgstr "" + +msgid "" +"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." +msgstr "" + +msgid "Will this transit benefit change my CalFresh account?" +msgstr "" + +msgid "No. Your monthly CalFresh allotment will not change." +msgstr "" + +msgid "Do I need my Golden State Advantage card to enroll?" +msgstr "" + +msgid "" +"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." +msgstr "" + +msgid "Can I use my Golden State Advantage card to pay for transit rides?" +msgstr "" + +msgid "" +"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." +msgstr "" + msgid "Go back" msgstr "" @@ -386,6 +425,20 @@ msgid "" "the transit benefit you selected." msgstr "" +msgid "CalFresh Cardholder" +msgstr "" + +msgid "You must have" +msgstr "" + +msgid "recently received CalFresh funds" +msgstr "" + +msgid "" +"This transit benefit will remain active for one year. You will need to " +"verify your identity with" +msgstr "" + msgid "MST Courtesy Card" msgstr "" diff --git a/benefits/locale/es/LC_MESSAGES/django.po b/benefits/locale/es/LC_MESSAGES/django.po index fbfdfce87..f290aa3c4 100644 --- a/benefits/locale/es/LC_MESSAGES/django.po +++ b/benefits/locale/es/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Report-Msgid-Bugs-To: https://github.com/cal-itp/benefits/issues \n" -"POT-Creation-Date: 2024-03-13 22:40+0000\n" +"POT-Creation-Date: 2024-03-20 18:12+0000\n" "Language: Español\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -469,6 +469,45 @@ msgid "A phone number with a phone plan associated with your name" msgstr "" "Un número de teléfono en el cual pueda recibir llamadas o mensajes de texto" +msgid "Learn more about the transit benefit for CalFresh Cardholders" +msgstr "" + +msgid "" +"How do I know if I'm eligible for the transit benefit for CalFresh " +"Cardholders?" +msgstr "" + +msgid "" +"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." +msgstr "" + +msgid "Will this transit benefit change my CalFresh account?" +msgstr "" + +msgid "No. Your monthly CalFresh allotment will not change." +msgstr "" + +msgid "Do I need my Golden State Advantage card to enroll?" +msgstr "" + +msgid "" +"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." +msgstr "" + +msgid "Can I use my Golden State Advantage card to pay for transit rides?" +msgstr "" + +msgid "" +"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." +msgstr "" + msgid "Go back" msgstr "Volver" @@ -489,6 +528,20 @@ msgstr "" "Utilizamos Login.gov para verificar su identidad para asegurarnos de que " "seas elegible para el beneficio de tránsito que seleccionaste." +msgid "CalFresh Cardholder" +msgstr "" + +msgid "You must have" +msgstr "" + +msgid "recently received CalFresh funds" +msgstr "" + +msgid "" +"This transit benefit will remain active for one year. You will need to " +"verify your identity with" +msgstr "" + msgid "MST Courtesy Card" msgstr "Tarjeta de cortesía de MST" diff --git a/benefits/settings.py b/benefits/settings.py index 35163a339..7e19d3e74 100644 --- a/benefits/settings.py +++ b/benefits/settings.py @@ -49,6 +49,7 @@ def RUNTIME_ENVIRONMENT(): "django.contrib.messages", "django.contrib.sessions", "django.contrib.staticfiles", + "adminsortable2", "django_google_sso", "benefits.core", "benefits.enrollment", diff --git a/pyproject.toml b/pyproject.toml index 1b2323b94..71c529665 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,7 @@ dependencies = [ "azure-identity==1.15.0", "Django==5.0.3", "django-csp==3.8", + "django-admin-sortable2==2.1.5", "django-google-sso==6.0.2", "eligibility-api==2023.9.1", "calitp-littlepay==2024.3.1", diff --git a/tests/cypress/specs/benefit-select.cy.js b/tests/cypress/specs/benefit-select.cy.js index 1d4f9c5ad..9ee369c5a 100644 --- a/tests/cypress/specs/benefit-select.cy.js +++ b/tests/cypress/specs/benefit-select.cy.js @@ -8,20 +8,20 @@ describe("Benefit selection", () => { helpers.selectAgency(); }); - it("User sees 3 radio buttons", () => { - cy.get("input:radio").should("have.length", 3); + it("User sees 4 radio buttons", () => { + cy.get("input:radio").should("have.length", 4); cy.contains("Courtesy Card"); cy.contains("65 years"); }); it("User must select a radio button, or else see a validation message", () => { - cy.get("input:radio").should("have.length", 3); + cy.get("input:radio").should("have.length", 4); cy.get("input:radio:checked").should("have.length", 0); cy.get("#form-verifier-selection").submit(); cy.url().should("include", verifier_selection_url); cy.get("input:radio:checked").should("have.length", 0); - cy.get("input:invalid").should("have.length", 3); + cy.get("input:invalid").should("have.length", 4); cy.get("input:radio") .first() .invoke("prop", "validationMessage")