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: add CalFresh option #1958

Merged
merged 7 commits into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
7 changes: 6 additions & 1 deletion benefits/core/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -17,7 +18,6 @@

for model in [
models.EligibilityType,
models.EligibilityVerifier,
models.PaymentProcessor,
models.PemData,
models.TransitAgency,
Expand All @@ -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")
Expand Down
Original file line number Diff line number Diff line change
@@ -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),
]
40 changes: 38 additions & 2 deletions benefits/core/migrations/local_fixtures.json
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -142,6 +152,7 @@
"pk": 2,
"fields": {
"name": "(MST) VA.gov - veteran",
"display_order": 3,
"active": true,
"api_url": null,
"api_auth_header": null,
Expand All @@ -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",
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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",
Expand All @@ -237,6 +252,27 @@
"form_class": "benefits.eligibility.forms.SBMTDMobilityPass"
}
},
{
"model": "core.eligibilityverifier",
"pk": 7,
"fields": {
"name": "CalFresh oauth claims via Login.gov",
thekaveman marked this conversation as resolved.
Show resolved Hide resolved
"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,
Expand Down Expand Up @@ -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]
}
},
{
Expand Down
4 changes: 4 additions & 0 deletions benefits/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{% extends "core/includes/modal.html" %}
{% load i18n %}
{% load static %}

{% block modal-content %}
<h2 class="me-4 me-md-0">{% translate "Learn more about the transit benefit for CalFresh Cardholders" %}</h2>
<div class="row">
<h3 class="pt-4">{% translate "How do I know if I'm eligible for the transit benefit for CalFresh Cardholders?" %}</h3>
<p class="pt-1">
{% 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>

<h3 class="pt-4">{% translate "Will this transit benefit change my CalFresh account?" %}</h3>
<p class="pt-1">
{% blocktranslate trimmed %}
No. Your monthly CalFresh allotment will not change.
{% endblocktranslate %}
</p>
<h3 class="pt-4">{% translate "Do I need my Golden State Advantage card to enroll?" %}</h3>
<p class="pt-1">
{% 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>
<h3 class="pt-4">{% translate "Can I use my Golden State Advantage card to pay for transit rides?" %}</h3>
<p class="pt-1">
{% 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>

<p class="pt-4 d-block d-sm-none">
<a href="#" data-bs-dismiss="modal" aria-label="Close">{% translate "Go back" %}</a>
</p>
</div>
{% endblock modal-content %}
Original file line number Diff line number Diff line change
@@ -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" %}
{% comment %} modal-trigger needs to be refactored to support translating the text {% endcomment %}
thekaveman marked this conversation as resolved.
Show resolved Hide resolved
{% include "core/includes/modal-trigger.html" with modal="modal--calfresh" text="recently received CalFresh funds" 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 %}
1 change: 1 addition & 0 deletions benefits/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ def RUNTIME_ENVIRONMENT():
"django.contrib.messages",
"django.contrib.sessions",
"django.contrib.staticfiles",
"adminsortable2",
"django_google_sso",
"benefits.core",
"benefits.enrollment",
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
8 changes: 4 additions & 4 deletions tests/cypress/specs/benefit-select.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
Loading