Repository: cal-itp/benefits

Issue:
Create app configuration for SBMTD+Agency card (Mobility Pass)
## Tasks

- [x] Define `EligibilityType` for "SBMTD Mobility Pass"
- [x] Define `EligiblityVerifier` using MST CC as an example
  - [x] Need a per-verifier `SERVER_PUBLIC_KEY_URL` variable
- [x] Define necessary includes/templates
- [x] Define form `SBMTDMobilityPass` with configuration (labels, helper, validation, etc.)
- [x] Update SBMTD `TransitAgency`
- [x] Update all relevant copy for English and Spanish

## Acceptance criteria

- [x] SBMTD user sees an option for "Mobility Pass" on the Eligibility Index page
- [x] Selecting "Mobility Pass" shows more info on the Eligibility Start page
- [x] Continuing shows the Eligibility Confirm page with rendered form / details
- [x] English and Spanish match [`SBMTD` tab of spreadsheet](https://docs.google.com/spreadsheets/d/1_Gi_YbJr4ZuXCOsnOWaewvHqUO1nC1nKqiVDHvw0118/edit#gid=536435981)
- [x] Help page update
- [x] Submitting the form with sample data (e.g. against a local `server`) correctly verifies eligible and ineligible users



Discussion:
## Mobility Pass validation details
- 4 digits, numbers only
- Last name

Blocking this until we have a deployment of the Eligibility Server for SBMTD.
Unblocking for Sprint 11, we can get started on this now that we are close to having a server live.
@thekaveman @angela-tran I'm thinking through this ticket. To get `Submitting the form with sample data (e.g. against a local server) correctly verifies eligible and ineligible users` to work correctly, I'll need to add 4-digit ID subs and name combinations to Eligibility Server (https://github.com/cal-itp/eligibility-server/blob/64e421d75306784945be7bd7fc57ee6ce1ecdd66/data/server.csv#L4 / https://github.com/cal-itp/eligibility-server/blob/64e421d75306784945be7bd7fc57ee6ce1ecdd66/data/server.json), right?


@machikoyasuda yep! Except let's just forget about the JSON version (https://github.com/cal-itp/eligibility-server/issues/348).

We also need the sample data to have the correct `type` value: `mobility_pass`.

Resolving patch:
diff --git a/benefits/core/migrations/0002_data.py b/benefits/core/migrations/0002_data.py
--- a/benefits/core/migrations/0002_data.py
+++ b/benefits/core/migrations/0002_data.py
@@ -28,13 +28,25 @@ def load_data(app, *args, **kwargs):
     sbmtd_senior_type = EligibilityType.objects.create(
         name="senior", label="Senior Discount (SBMTD)", group_id=os.environ.get("SBMTD_SENIOR_GROUP_ID", "group4")
     )
+    sbmtd_mobility_pass_type = EligibilityType.objects.create(
+        name="mobility_pass",
+        label="Mobility Pass Discount (SBMTD)",
+        group_id=os.environ.get("SBMTD_MOBILITY_PASS_GROUP_ID", "group5"),
+    )
 
     PemData = app.get_model("core", "PemData")
 
-    server_public_key = PemData.objects.create(
+    mst_server_public_key = PemData.objects.create(
         label="Eligibility server public key",
         remote_url=os.environ.get(
-            "SERVER_PUBLIC_KEY_URL", "https://raw.githubusercontent.com/cal-itp/eligibility-server/dev/keys/server.pub"
+            "MST_SERVER_PUBLIC_KEY_URL", "https://raw.githubusercontent.com/cal-itp/eligibility-server/dev/keys/server.pub"
+        ),
+    )
+
+    sbmtd_server_public_key = PemData.objects.create(
+        label="Eligibility server public key",
+        remote_url=os.environ.get(
+            "SBMTD_SERVER_PUBLIC_KEY_URL", "https://raw.githubusercontent.com/cal-itp/eligibility-server/dev/keys/server.pub"
         ),
     )
 
@@ -192,7 +204,7 @@ def load_data(app, *args, **kwargs):
         api_auth_header=os.environ.get("COURTESY_CARD_VERIFIER_API_AUTH_HEADER", "X-Server-API-Key"),
         api_auth_key=os.environ.get("COURTESY_CARD_VERIFIER_API_AUTH_KEY", "server-auth-token"),
         eligibility_type=mst_courtesy_card_type,
-        public_key=server_public_key,
+        public_key=mst_server_public_key,
         jwe_cek_enc=os.environ.get("COURTESY_CARD_VERIFIER_JWE_CEK_ENC", "A256CBC-HS512"),
         jwe_encryption_alg=os.environ.get("COURTESY_CARD_VERIFIER_JWE_ENCRYPTION_ALG", "RSA-OAEP"),
         jws_signing_alg=os.environ.get("COURTESY_CARD_VERIFIER_JWS_SIGNING_ALG", "RS256"),
@@ -220,6 +232,23 @@ def load_data(app, *args, **kwargs):
         start_template="eligibility/start--senior.html",
     )
 
+    sbmtd_mobility_pass_verifier = EligibilityVerifier.objects.create(
+        name=os.environ.get("MOBILITY_PASS_VERIFIER_NAME", "Eligibility Server Verifier"),
+        active=os.environ.get("MOBILITY_PASS_VERIFIER_ACTIVE", "True").lower() == "true",
+        api_url=os.environ.get("MOBILITY_PASS_VERIFIER_API_URL", "http://server:8000/verify"),
+        api_auth_header=os.environ.get("MOBILITY_PASS_VERIFIER_API_AUTH_HEADER", "X-Server-API-Key"),
+        api_auth_key=os.environ.get("MOBILITY_PASS_VERIFIER_API_AUTH_KEY", "server-auth-token"),
+        eligibility_type=sbmtd_mobility_pass_type,
+        public_key=sbmtd_server_public_key,
+        jwe_cek_enc=os.environ.get("MOBILITY_PASS_VERIFIER_JWE_CEK_ENC", "A256CBC-HS512"),
+        jwe_encryption_alg=os.environ.get("MOBILITY_PASS_VERIFIER_JWE_ENCRYPTION_ALG", "RSA-OAEP"),
+        jws_signing_alg=os.environ.get("MOBILITY_PASS_VERIFIER_JWS_SIGNING_ALG", "RS256"),
+        auth_provider=None,
+        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",
+    )
+
     PaymentProcessor = app.get_model("core", "PaymentProcessor")
 
     mst_payment_processor = PaymentProcessor.objects.create(
@@ -337,9 +366,10 @@ def load_data(app, *args, **kwargs):
         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",
     )
-    sbmtd_agency.eligibility_types.set([sbmtd_senior_type])
-    sbmtd_agency.eligibility_verifiers.set([sbmtd_senior_verifier])
+    sbmtd_agency.eligibility_types.set([sbmtd_senior_type, sbmtd_mobility_pass_type])
+    sbmtd_agency.eligibility_verifiers.set([sbmtd_senior_verifier, sbmtd_mobility_pass_verifier])
 
 
 class Migration(migrations.Migration):
diff --git a/benefits/eligibility/forms.py b/benefits/eligibility/forms.py
--- a/benefits/eligibility/forms.py
+++ b/benefits/eligibility/forms.py
@@ -156,3 +156,26 @@ def __init__(self, *args, **kwargs):
             *args,
             **kwargs,
         )
+
+
+class SBMTDMobilityPass(EligibilityVerificationForm):
+    """EligibilityVerification form for the SBMTD Mobility Pass."""
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(
+            title=_("Agency card information"),
+            headline=_("Let’s see if we can confirm your eligibility."),
+            blurb=_("Please input your Mobility Pass number and last name below to confirm your eligibility."),
+            name_label=_("Last name (as it appears on Mobility Pass)"),
+            name_placeholder="Garcia",
+            name_help_text=_("We use this to help confirm your Mobility Pass."),
+            sub_label=_("SBMTD Mobility Pass number"),
+            sub_help_text=_("This is a 4-digit number on the front and back of your card."),
+            sub_placeholder="1234",
+            name_max_length=255,
+            sub_input_mode="numeric",
+            sub_max_length=4,
+            sub_pattern=r"\d{4}",
+            *args,
+            **kwargs,
+        )


Test patch: