2025-12-23 15:19:20 +09:00
# Eligibility & Verification
2025-12-18 18:12:20 +09:00
2025-12-23 15:19:20 +09:00
This guide describes how eligibility and verification work in the customer portal:
2025-12-18 18:12:20 +09:00
2025-12-23 15:19:20 +09:00
- **Internet eligibility** (NTT serviceability review)
2025-12-24 19:01:21 +09:00
- **ID verification** (residence card / identity document) for all services
2025-12-18 18:12:20 +09:00
2025-12-23 15:19:20 +09:00
## Overview
2025-12-18 18:12:20 +09:00
2025-12-23 15:19:20 +09:00
| Concept | Source of Truth | Description |
2025-12-18 18:12:20 +09:00
| --------------------------- | ------------------------------------------- | -------------------------------- |
| Products + pricing | Salesforce pricebook | Single catalog truth |
2025-12-23 15:19:20 +09:00
| Payment methods | WHMCS | Card storage via Stripe |
2025-12-18 18:12:20 +09:00
| Orders + fulfillment | Salesforce Order (and downstream WHMCS) | Operational workflow |
| Internet eligibility status | Salesforce Account (with Case for workflow) | Reuse for future internet orders |
2025-12-24 19:01:21 +09:00
| ID verification status | Salesforce Account (with Files) | Reuse for future orders |
2025-12-18 18:12:20 +09:00
2025-12-23 15:19:20 +09:00
## Internet Eligibility (NTT Address Review)
### How It Works
2025-12-24 19:01:21 +09:00
1. Customer navigates to `/account/services/internet`
2025-12-25 15:48:57 +09:00
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 & Rate Limiting (Security + Load)
- **BFF cache (Redis)**:
- Internet catalog data is cached in Redis (CDC-driven invalidation, no TTL) so repeated portal hits **do not repeatedly query Salesforce** .
- Eligibility details are cached per Salesforce Account ID and are invalidated/updated when Salesforce emits Account change events.
- **Portal cache (React Query)**:
- The portal caches service catalog responses in-memory, scoped by auth state, and will refetch when stale.
- On logout, the portal clears cached queries to avoid cross-user leakage on shared devices.
- **Rate limiting**:
- Public catalog endpoints are rate-limited per IP + User-Agent to prevent abuse.
- `POST /api/services/internet/eligibility-request` is authenticated and rate-limited, and the BFF is idempotent when a request is already pending (no duplicate Cases created).
2025-12-23 15:19:20 +09:00
### 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 |
2025-12-25 15:48:57 +09:00
**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.
2025-12-23 15:19:20 +09:00
### Status Values
2025-12-25 15:48:57 +09:00
| Status | Services Page UI | Checkout Gating |
2025-12-23 15:19:20 +09:00
| --------------- | --------------------------------------- | --------------- |
| `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 |
2025-12-24 19:01:21 +09:00
## ID Verification (Residence Card)
2025-12-23 15:19:20 +09:00
### 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
2025-12-24 19:01:21 +09:00
5. Customer sees "Verified" status and can submit orders
2025-12-23 15:19:20 +09:00
### 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
2025-12-24 19:01:21 +09:00
| 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 |
2025-12-23 15:19:20 +09:00
### Supported File Types
- PDF
- PNG
- JPG/JPEG
## Portal UI Locations
2025-12-25 15:48:57 +09:00
| 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.) |
2025-12-23 15:19:20 +09:00
## 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.