# Eligibility & Verification

This guide describes how eligibility and verification work in the customer portal:

- **Internet eligibility** (NTT serviceability review)
- **ID verification** (residence card / identity document) for all services

## Overview

| Concept                     | Source of Truth                             | Description                      |
| --------------------------- | ------------------------------------------- | -------------------------------- |
| Products + pricing          | Salesforce pricebook                        | Single catalog truth             |
| Payment methods             | WHMCS                                       | Card storage via Stripe          |
| Orders + fulfillment        | Salesforce Order (and downstream WHMCS)     | Operational workflow             |
| Internet eligibility status | Salesforce Account (with Case for workflow) | Reuse for future internet orders |
| ID verification status      | Salesforce Account (with Files)             | Reuse for future orders          |

## Internet Eligibility (NTT Address Review)

### How It Works

1. Customer navigates to `/account/services/internet`
2. Customer clicks **Check Availability** (requires a service address on file)
3. Portal calls `POST /api/services/internet/eligibility-request` and shows an immediate confirmation screen at `/account/services/internet/request-submitted`
4. Portal **finds/creates a Salesforce Opportunity** (Stage = `Introduction`) and creates a Salesforce Case **linked to that Opportunity** for agent review
5. Agent performs NTT serviceability check (manual process)
6. Agent updates Account eligibility fields
7. Salesforce Flow sends email notification to customer
8. Customer returns and sees eligible plans

### Caching & Real-Time Updates

#### Redis Caching (BFF)

| Cache Key                           | Content                     | Invalidation   |
| ----------------------------------- | --------------------------- | -------------- |
| `services:eligibility:{accountId}`  | Eligibility status & value  | Platform Event |
| `services:verification:{accountId}` | Verification status & dates | Platform Event |

Both caches use CDC-driven invalidation with a safety TTL (12 hours default). When Salesforce sends a Platform Event, the BFF:

1. Invalidates both caches (eligibility + verification)
2. Sends SSE `account.updated` to connected portals
3. Portal refetches fresh data

#### Platform Event Integration

See `docs/integrations/salesforce/platform-events.md` for full details.

**Account Update Event** fires when any of these fields change:

- `Internet_Eligibility__c`, `Internet_Eligibility_Status__c`
- `Id_Verification_Status__c`, `Id_Verification_Rejection_Message__c`

The Flow should use `ISCHANGED()` to only include status fields when they actually changed (not on every field change).

#### Portal Cache (React Query)

- Service catalog responses are cached in-memory, scoped by auth state
- SSE events trigger automatic refetch
- On logout, cached queries are cleared

#### Rate Limiting

- Public catalog endpoints: rate-limited per IP + User-Agent
- `POST /api/services/internet/eligibility-request`: authenticated, rate-limited, idempotent

### Subscription Type Detection

The portal identifies Internet subscriptions by product name matching:

```typescript
// Matches any of these patterns (case-insensitive):
// - "internet"
// - "sonixnet"
// - "ntt" + "fiber"
const isInternetService =
  productName.includes("internet") ||
  productName.includes("sonixnet") ||
  (productName.includes("ntt") && productName.includes("fiber"));
```

### Salesforce Account Fields

| Field API Name                              | Type     | Set By       | When          |
| ------------------------------------------- | -------- | ------------ | ------------- |
| `Internet_Eligibility_Status__c`            | Picklist | Portal/Agent | Request/Check |
| `Internet_Eligibility__c`                   | Text     | Agent        | After check   |
| `Internet_Eligibility_Request_Date_Time__c` | DateTime | Portal       | On request    |
| `Internet_Eligibility_Checked_Date_Time__c` | DateTime | Agent        | After check   |

**Notes:**

- The portal returns an API-level **request id** (Salesforce Case ID) from `POST /api/services/internet/eligibility-request` for display/auditing.
- The portal UI reads eligibility status/value from the Account fields above; it does not rely on an Account-stored Case ID.

### Status Values

| Status          | Services Page UI                        | Checkout Gating |
| --------------- | --------------------------------------- | --------------- |
| `Not Requested` | Show "Request eligibility check" button | Block submit    |
| `Pending`       | Show "Review in progress"               | Block submit    |
| `Eligible`      | Show eligible plans                     | Allow submit    |
| `Ineligible`    | Show "Not available" + contact support  | Block submit    |

## ID Verification (Residence Card)

### How It Works

1. Customer navigates to `/account/settings` (Profile page)
2. Customer uploads residence card in the "Identity Verification" section
3. File is uploaded to Salesforce (ContentVersion linked to Account)
4. Agent reviews document and updates verification status
5. Customer sees "Verified" status and can submit orders

### Where to Upload

ID verification is available in two places:

1. **Profile Page** (`/account/settings`) - Integrated upload in the "Identity Verification" card
2. **Standalone Page** (`/account/settings/verification`) - For checkout flow redirects

The Profile page is the primary location. The standalone page is used when redirecting from checkout with a `returnTo` parameter.

### Salesforce Account Fields

| Field API Name                           | Type     | Set By       | When          |
| ---------------------------------------- | -------- | ------------ | ------------- |
| `Id_Verification_Status__c`              | Picklist | Portal/Agent | Upload/Review |
| `Id_Verification_Submitted_Date_Time__c` | DateTime | Portal       | On upload     |
| `Id_Verification_Verified_Date_Time__c`  | DateTime | Agent        | After review  |
| `Id_Verification_Note__c`                | Text     | Agent        | After review  |
| `Id_Verification_Rejection_Message__c`   | Text     | Agent        | If rejected   |

### Status Values

| Status          | Portal UI                               | Can Submit Order? |
| --------------- | --------------------------------------- | ----------------: |
| `Not Submitted` | Show upload form                        |                No |
| `Submitted`     | Show "Under Review" with submitted info |               Yes |
| `Verified`      | Show "Verified" badge                   |               Yes |
| `Rejected`      | Show rejection reason + upload form     |                No |

### Supported File Types

- PDF
- PNG
- JPG/JPEG

## Portal UI Locations

| Location                                       | What's Shown                                                   |
| ---------------------------------------------- | -------------------------------------------------------------- |
| `/account/settings`                            | Profile, Address, ID Verification (with upload)                |
| `/account/services/internet`                   | Eligibility status and eligible plans                          |
| `/account/services/internet/request-submitted` | Immediate confirmation after submitting an eligibility request |
| Subscription detail                            | Service-specific actions (cancel, etc.)                        |

## Cancellation Flow

### Internet Cancellation

1. Customer navigates to subscription detail → clicks "Request Cancellation"
2. Portal creates Salesforce Case with WHMCS Service ID
3. Portal updates Opportunity with cancellation data:
   - `ScheduledCancellationDateAndTime__c` = end of cancellation month
   - `CancellationNotice__c` = "有" (received)
   - `LineReturn__c` = "NotYet"
4. Agent processes Case:
   - Terminates WHMCS service on scheduled date
   - Updates `LineReturn__c` for equipment return tracking
   - Updates Opportunity to "〇Cancelled"

**Note:** WHMCS service termination is manual (agent work). The portal updates Salesforce, but does not automatically terminate in WHMCS.

### SIM Cancellation

1. Customer navigates to subscription detail → SIM Management → Cancel
2. Portal calls Freebit PA02-04 cancellation API
3. Service is scheduled for cancellation at end of selected month

## Opportunity ↔ WHMCS Linking

### How They're Connected

After order provisioning, the Opportunity is linked to WHMCS via:

```
Opportunity.WHMCS_Service_ID__c = WHMCS Service ID (e.g., 456)
```

### Provisioning Flow

1. Order placed → Opportunity created (Stage = "Post Processing")
2. Order approved → Fulfillment runs
3. WHMCS `AddOrder` API called → returns `serviceIds`
4. Opportunity updated:
   - `WHMCS_Service_ID__c` = service ID from WHMCS
   - `StageName` = "Active"

### Finding Opportunity for Cancellation

When customer requests cancellation, the portal:

1. Takes WHMCS subscription ID from the portal
2. Queries Salesforce: `WHERE WHMCS_Service_ID__c = {subscriptionId}`
3. Updates the found Opportunity with cancellation data

### If Opportunity is Cancelled but WHMCS is Not

This can happen if the agent doesn't complete the WHMCS termination. Result:

- Customer continues to be billed (WHMCS active)
- Service remains active (not terminated)
- Salesforce says cancelled, WHMCS says active

**Prevention:** Agent must follow Case instructions to terminate WHMCS service on the scheduled date.

## Customer Profile Data

### Data Sources

| Field           | Source                       | Editable in Portal? |
| --------------- | ---------------------------- | ------------------- |
| Email           | Portal DB / WHMCS            | Yes                 |
| Phone Number    | WHMCS                        | Yes                 |
| First Name      | WHMCS                        | No (read-only)      |
| Last Name       | WHMCS                        | No (read-only)      |
| Customer Number | WHMCS Custom Field (ID: 198) | No (read-only)      |
| Date of Birth   | WHMCS Custom Field (ID: 201) | No (read-only)      |
| Gender          | WHMCS Custom Field (ID: 200) | No (read-only)      |
| Address         | WHMCS                        | Yes                 |

### Environment Variables

```bash
# WHMCS custom field IDs (must match your WHMCS installation)
WHMCS_CUSTOMER_NUMBER_FIELD_ID=198  # Default
WHMCS_DOB_FIELD_ID=201              # Default
WHMCS_GENDER_FIELD_ID=200           # Default
```

If customer number, DOB, or gender aren't showing, verify these field IDs match your WHMCS custom fields.
