Assist_Design/docs/integrations/salesforce/opportunity-lifecycle.md
barsa 6096c15659 Refactor Salesforce Opportunity Integration for SIM and Internet Cancellations
- Updated opportunity field mappings to replace deprecated fields with new ones for SIM and Internet cancellations, enhancing clarity and consistency.
- Introduced separate data structures for Internet and SIM cancellation data, improving type safety and validation.
- Refactored SalesforceOpportunityService to handle updates for both Internet and SIM cancellations, ensuring accurate data handling.
- Enhanced cancellation query fields to support new SIM cancellation requirements, improving the overall cancellation process.
- Cleaned up the portal integration to reflect changes in opportunity source fields, promoting better data integrity and tracking.
2026-01-05 17:08:33 +09:00

37 KiB

Opportunity Lifecycle Management Guide

This guide documents the Salesforce Opportunity integration for service lifecycle tracking.

Table of Contents

  1. Overview
  2. Existing Field Architecture
  3. Opportunity Matching Rules
  4. Internet Eligibility Flow
  5. ID Verification Flow
  6. Order Placement Flow
  7. Service Activation Flow
  8. Cancellation Flow
  9. Implementation Checklist

Overview

What Customers See vs What's Internal

┌─────────────────────────────────────────────────────────────────────────┐
│                    INTERNAL ONLY (Sales/CS Pipeline)                     │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  Opportunity Stages: Introduction, Ready (before Order placed)          │
│  Application Stages: INTRO-1, UNRESPONSIVE-1, etc. (CS workflow)        │
│  Eligibility fields on Account (eligibility status)                     │
│  ID Verification fields on Account (verification status)                │
│                                                                          │
│  These are for internal tracking - customer sees results, not fields.   │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────┐
│                    CUSTOMER-FACING (Portal)                              │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  1. ELIGIBILITY STATUS (from Account field)                              │
│     └─ "Checking...", "Eligible", "Not Eligible"                         │
│                                                                          │
│  2. ID VERIFICATION STATUS (from Account field)                          │
│     └─ "Pending", "Verified", "Rejected"                                 │
│                                                                          │
│  3. ORDER TRACKING (from Salesforce Order)                               │
│     └─ After order placed, before WHMCS activates                        │
│                                                                          │
│  4. SERVICE PAGE (from WHMCS)                                            │
│     └─ After service is active                                           │
│                                                                          │
│  5. CANCELLATION STATUS (from Opportunity)                               │
│     └─ End date, return deadline, kit status                             │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

Existing Field Architecture

Account Fields (Already Exist)

Internet Eligibility Fields:

Field API Name Purpose
Eligibility Value Internet_Eligibility__c The actual eligibility result
Status Internet_Eligibility_Status__c Pending, Checked
Requested At Internet_Eligibility_Request_Date_Time__c When request was made
Checked At Internet_Eligibility_Checked_Date_Time__c When eligibility was checked

Notes:

  • The portal does not store the Case ID or agent notes on the Account in our current Salesforce environment.
  • Agent notes should live inside the Case Description / Case activity history.

ID Verification Fields:

Field API Name Purpose
Status Id_Verification_Status__c Pending, Verified, Rejected
Submitted At Id_Verification_Submitted_Date_Time__c When submitted
Verified At Id_Verification_Verified_Date_Time__c When verified
Notes Id_Verification_Note__c Agent notes
Rejection Message Id_Verification_Rejection_Message__c Reason for rejection

Opportunity Fields (Existing)

Core Fields:

Field API Name Purpose
Stage StageName Introduction, Ready, Post Processing, Active, △Cancelling, etc.
Commodity Type CommodityType Personal SonixNet Home Internet, SIM, VPN
Application Stage Application_Stage__c INTRO-1 (for portal)

Internet Cancellation Fields:

Field API Name Purpose
Cancellation Notice CancellationNotice__c 有, 未, 不要, 移転
Scheduled Cancellation ScheduledCancellationDateAndTime__c End of cancellation month
Line Return Status LineReturn__c NotYet, SentKit, Returned, etc

SIM Cancellation Fields:

Field API Name Purpose
SIM Cancellation Notice SIMCancellationNotice__c 有, 未, 不要
SIM Scheduled Cancellation SIMScheduledCancellationDateAndTime__c End of SIM cancellation

Note: SIM customer comments are stored on the Cancellation Case, same as Internet.

Portal Integration Fields (Existing)

Field API Name Type Purpose
Opportunity Source Opportunity_Source__c Picklist How Opportunity was created
WHMCS Service ID WHMCS_Service_ID__c Number Link to WHMCS after provisioning

Order Fields (Existing)

Field API Name Purpose
Opportunity OpportunityId Links Order TO Opportunity

Case Fields (Existing)

Field API Name Purpose
Opportunity OpportunityId Links Case TO Opportunity

Key Principle: Cases and Orders link TO Opportunity, not vice versa.


Opportunity Matching Rules

When to Find vs Create Opportunity

┌─────────────────────────────────────────────────────────────────────────┐
│                     OPPORTUNITY MATCHING RULES                           │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  INTERNET ELIGIBILITY REQUEST:                                           │
│  ─────────────────────────────                                           │
│  1. Check if Account already has eligibility status set                  │
│     └─ If already "Eligible" or "Not Eligible" → Don't create Opp       │
│                                                                          │
│  2. Find existing Opportunity:                                           │
│     └─ WHERE AccountId = ?                                               │
│       AND CommodityType IN ('Personal SonixNet Home Internet',          │
│                              'Corporate SonixNet Home Internet')         │
│       AND StageName = 'Introduction'                                     │
│       AND IsClosed = false                                               │
│                                                                          │
│  3. If found → Use existing, create Case linked to it                    │
│     If not → Create new Opportunity, then create Case linked to it       │
│                                                                          │
│  ORDER PLACEMENT:                                                        │
│  ─────────────────                                                       │
│  1. Find existing Opportunity:                                           │
│     └─ WHERE AccountId = ?                                               │
│       AND CommodityType = ? (based on order type)                        │
│       AND StageName IN ('Introduction', 'Ready')                         │
│       AND IsClosed = false                                               │
│                                                                          │
│  2. If found → Use existing, update stage to 'Post Processing'           │
│     If not → Create new Opportunity with stage 'Post Processing'         │
│                                                                          │
│  3. Create Order with Order.OpportunityId = Opportunity.Id               │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

Stage Matching by Flow

Flow Match Stages If Not Found
Internet Eligibility Introduction only Create with Introduction
Order Placement Introduction, Ready Create with Post Processing
Provisioning Post Processing Error (should exist from order)
Cancellation Active Error (service must be active)

Internet Eligibility Flow

Complete Flow Diagram

┌─────────────────────────────────────────────────────────────────────────┐
│                     INTERNET ELIGIBILITY FLOW                            │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  1. CUSTOMER ENTERS ADDRESS                                              │
│     └─ Portal: POST /api/services/internet/eligibility-request           │
│        Portal UI: shows confirmation at /account/services/internet/request-submitted │
│                                                                          │
│  2. CHECK IF ELIGIBILITY ALREADY KNOWN                                   │
│     └─ Query: SELECT Internet_Eligibility__c FROM Account                │
│     └─ If already set → Return cached result, no action needed           │
│                                                                          │
│  3. FIND OR CREATE OPPORTUNITY                                           │
│     ┌─────────────────────────────────────────────────────────────────┐ │
│     │ Query:                                                          │ │
│     │   SELECT Id FROM Opportunity                                    │ │
│     │   WHERE AccountId = ?                                           │ │
│     │     AND CommodityType IN ('Personal SonixNet Home Internet',    │ │
│     │                           'Corporate SonixNet Home Internet')   │ │
│     │     AND StageName = 'Introduction'                              │ │
│     │     AND IsClosed = false                                        │ │
│     │                                                                 │ │
│     │ If found → Use existing                                         │ │
│     │ If not → Create new:                                            │ │
│     │   - Stage: Introduction                                         │ │
│     │   - CommodityType: Personal SonixNet Home Internet              │ │
│     │   - Opportunity_Source__c: Portal - Internet Eligibility Request│ │
│     │   - Application_Stage__c: INTRO-1                               │ │
│     └─────────────────────────────────────────────────────────────────┘ │
│                                                                          │
│  4. CREATE CASE (linked to Opportunity)                                  │
│     ┌─────────────────────────────────────────────────────────────────┐ │
│     │ Case.Type = "Eligibility Check"                                 │ │
│     │ Case.AccountId = customer's account                             │ │
│     │ Case.OpportunityId = opportunity from step 3 ←── THE LINK       │ │
│     │ Case.Subject = "Internet Eligibility - {Address}"               │ │
│     │ Case.Description = address details, postal code, etc.           │ │
│     │ Case.Status = "New"                                             │ │
│     └─────────────────────────────────────────────────────────────────┘ │
│                                                                          │
│  5. UPDATE ACCOUNT                                                       │
│     └─ Internet_Eligibility_Status__c = "Pending"                        │
│     └─ Internet_Eligibility_Request_Date_Time__c = now()                 │
│                                                                          │
│  6. CS PROCESSES CASE                                                    │
│     └─ Checks with NTT / provider                                        │
│     └─ Updates Account:                                                  │
│         - Internet_Eligibility__c = result                               │
│         - Internet_Eligibility_Status__c = "Checked"                     │
│         - Internet_Eligibility_Checked_Date_Time__c = now()              │
│     └─ Opportunity stages are not automatically moved to "Ready" by      │
│        the eligibility check. CS updates stages later as part of the     │
│        order review / lifecycle workflow.                                │
│                                                                          │
│  7. PORTAL DETECTS CHANGE (via CDC or polling)                           │
│     └─ Shows eligibility result to customer                              │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

What Customer Sees

Account Field State Portal Shows
Status = null Address input form
Status = "Pending" "Checking your address..." spinner
Eligibility = eligible value Plan selection enabled
Eligibility = not eligible "Sorry, service not available" message

ID Verification Flow

Complete Flow Diagram

┌─────────────────────────────────────────────────────────────────────────┐
│                     ID VERIFICATION (eKYC) FLOW                          │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  WHEN: During checkout registration or before order placement            │
│                                                                          │
│  1. CHECK IF ALREADY VERIFIED                                            │
│     └─ Query: SELECT Id_Verification_Status__c FROM Account              │
│     └─ If "Verified" → Skip verification, proceed to checkout            │
│                                                                          │
│  2. CUSTOMER UPLOADS ID DOCUMENTS                                        │
│     └─ Portal: POST /api/verification/residence-card                     │
│     └─ BFF uploads file to Salesforce Files (ContentVersion)             │
│                                                                          │
│  3. UPDATE ACCOUNT                                                       │
│     └─ Id_Verification_Status__c = "Submitted" (portal maps to pending)  │
│     └─ Id_Verification_Submitted_Date_Time__c = now()                    │
│                                                                          │
│  4. CS REVIEWS IN SALESFORCE                                              │
│     └─ Id_Verification_Status__c = "Verified" or "Rejected"              │
│     └─ Id_Verification_Verified_Date_Time__c = now() (on verify)          │
│     └─ Id_Verification_Rejection_Message__c = reason (on reject)          │
│                                                                          │
│  5. CUSTOMER RESUBMITS IF NEEDED                                          │
│     └─ Portal shows feedback + upload UI                                 │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

What Customer Sees

Account Field State Portal Shows
Status = null ID upload form
Status = "Pending" "Verifying your identity..."
Status = "Verified" Proceed to checkout enabled
Status = "Rejected" Error message + resubmit option

Order Placement Flow

┌─────────────────────────────────────────────────────────────────────────┐
│                     ORDER PLACEMENT FLOW                                 │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  PREREQUISITES:                                                          │
│  - Internet: Eligibility = Eligible (Account field)                      │
│  - SIM: ID Verification = Verified (Account field)                       │
│                                                                          │
│  1. CUSTOMER SUBMITS ORDER                                               │
│     └─ Portal: POST /api/orders                                          │
│                                                                          │
│  2. FIND OR CREATE OPPORTUNITY                                           │
│     └─ Query for existing (Introduction or Ready stage)                  │
│     └─ If found → Use existing                                           │
│     └─ If not → Create with stage 'Post Processing'                      │
│                                                                          │
│  3. CREATE SALESFORCE ORDER                                              │
│     └─ Order.OpportunityId = Opportunity.Id ←── THE LINK                 │
│     └─ Order.Status = "Pending Review"                                   │
│                                                                          │
│  4. UPDATE OPPORTUNITY                                                   │
│     └─ Stage = "Post Processing"                                         │
│                                                                          │
│  5. CUSTOMER SEES ORDER TRACKING                                         │
│     └─ "Your order is being processed"                                   │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

Service Activation Flow

┌─────────────────────────────────────────────────────────────────────────┐
│                     SERVICE ACTIVATION FLOW                              │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  1. AGENT APPROVES ORDER                                                 │
│     └─ Order.Status = "Approved" (triggers CDC)                          │
│                                                                          │
│  2. BFF PROVISIONS TO WHMCS                                              │
│     └─ Calls WHMCS AddOrder API                                          │
│     └─ Passes OpportunityId as custom field ←── WHMCS GETS OPP ID       │
│     └─ WHMCS returns serviceId                                           │
│                                                                          │
│  3. UPDATE OPPORTUNITY                                                   │
│     └─ WHMCS_Service_ID__c = serviceId ←── OPP GETS WHMCS ID            │
│     └─ Stage = "Active"                                                  │
│                                                                          │
│  4. BIDIRECTIONAL LINK COMPLETE                                          │
│     └─ Opportunity.WHMCS_Service_ID__c → WHMCS Service                   │
│     └─ WHMCS Service.OpportunityId → Opportunity (optional; helpful for ops/debugging) │
│                                                                          │
│  5. CUSTOMER SEES SERVICE PAGE                                           │
│     └─ Portal shows active services from WHMCS; lifecycle/cancellation tracking lives on the linked Salesforce Opportunity (via WHMCS_Service_ID__c) │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

Cancellation Flow

The cancellation process differs between Internet and SIM services:

Internet Cancellation Flow

For Internet cancellation, we create a Case for CS workflow and update the Opportunity:

┌─────────────────────────────────────────────────────────────────────────┐
│                     INTERNET CANCELLATION FLOW                           │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  1. CUSTOMER SUBMITS CANCELLATION FORM                                   │
│     └─ Selects month (25th rule applies)                                 │
│     └─ Enters comments, alternative email (optional)                     │
│                                                                          │
│  2. CREATE CANCELLATION CASE                                             │
│     ┌─────────────────────────────────────────────────────────────────┐ │
│     │ Case.Type = "Cancellation Request"                              │ │
│     │ Case.AccountId = customer's account                             │ │
│     │ Case.Subject = "Cancellation Request - Internet ({month})"      │ │
│     │ Case.Description = ALL form data                                │ │
│     │ Case.OpportunityId = linked Opportunity (if found)              │ │
│     └─────────────────────────────────────────────────────────────────┘ │
│                                                                          │
│  3. IF OPPORTUNITY IS LINKED (via WHMCS_Service_ID__c)                   │
│     └─ Update Opportunity:                                               │
│         - Stage = "△Cancelling"                                          │
│         - ScheduledCancellationDateAndTime__c = end of month             │
│         - CancellationNotice__c = "有"                                   │
│         - LineReturn__c = "NotYet"                                       │
│                                                                          │
│  4. SEND CONFIRMATION EMAIL                                              │
│     └─ Customer receives confirmation with cancellation details          │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

SIM Cancellation Flow

For SIM cancellation, we call Freebit API, create a Case, and update the Opportunity:

┌─────────────────────────────────────────────────────────────────────────┐
│                     SIM CANCELLATION FLOW                                │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  1. CUSTOMER SUBMITS CANCELLATION FORM                                   │
│     └─ Selects month (25th rule applies)                                 │
│     └─ Sees minimum contract warning if applicable                       │
│                                                                          │
│  2. CALL FREEBIT PA02-04 API                                             │
│     └─ Cancel account with runDate = 1st of next month                   │
│     └─ Cancellation takes effect at end of selected month                │
│                                                                          │
│  3. CREATE CANCELLATION CASE (same as Internet)                          │
│     ┌─────────────────────────────────────────────────────────────────┐ │
│     │ Case.Type = "Cancellation Request"                              │ │
│     │ Case.AccountId = customer's account                             │ │
│     │ Case.Subject = "Cancellation Request - SIM ({month})"           │ │
│     │ Case.Description = ALL form data (SIM #, comments, etc.)        │ │
│     │ Case.OpportunityId = linked Opportunity (if found)              │ │
│     └─────────────────────────────────────────────────────────────────┘ │
│                                                                          │
│  4. IF OPPORTUNITY IS LINKED (via WHMCS_Service_ID__c)                   │
│     └─ Update Opportunity:                                               │
│         - Stage = "△Cancelling"                                          │
│         - SIMScheduledCancellationDateAndTime__c = end of month          │
│         - SIMCancellationNotice__c = "有"                                │
│                                                                          │
│  5. SEND CONFIRMATION EMAILS                                             │
│     └─ Admin notification with API results                               │
│     └─ Customer confirmation with cancellation details                   │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

The 25th Rule

TODAY'S DATE              AVAILABLE CANCELLATION MONTHS
─────────────────────────────────────────────────────────
Before 25th of month  →   Can select THIS month or later
On/After 25th         →   Must select NEXT month or later

Cancellation Data Location

Internet Cancellation:

Data Where It Goes Why
Scheduled date Opportunity Lifecycle tracking
Notice status Opportunity Lifecycle tracking
Return status Opportunity Equipment tracking (ONU)
Customer comments Case Details for CS
WHMCS Service ID Case Service identification

SIM Cancellation:

Data Where It Goes Why
Scheduled date Opportunity Lifecycle tracking
Notice status Opportunity Lifecycle tracking
Customer comments Case Same as Internet
SIM #, Serial # Case Service identification
WHMCS Service ID Case Helps CS identify service

Implementation Checklist

Salesforce Admin Tasks

Existing Fields (No Changes):

  • Opportunity Stage picklist
  • CommodityType field
  • Application_Stage__c
  • Account Internet eligibility fields
  • Account ID verification fields
  • Case.OpportunityId (standard lookup)
  • Order.OpportunityId (standard lookup)

Internet Cancellation Fields (Existing):

  • CancellationNotice__c - Internet cancellation notice status
  • LineReturn__c - Equipment return status
  • ScheduledCancellationDateAndTime__c - Internet cancellation date

SIM Cancellation Fields (Existing):

  • SIMCancellationNotice__c - SIM cancellation notice status
  • SIMScheduledCancellationDateAndTime__c - SIM cancellation date
  • Note: Customer comments stored on Case, same as Internet

Portal Integration Fields (Existing):

  • Opportunity_Source__c picklist (tracks how Opportunity was created)
  • WHMCS_Service_ID__c number field (links WHMCS → Salesforce for cancellations)

WHMCS Admin Tasks

  • Create an OpportunityId custom field on Services/Hosting (optional but recommended for ops/debugging)
  • Confirm whether your WHMCS expects customfields[] keys by name (OpportunityId) or by numeric field id, and configure accordingly

BFF Development Tasks

Completed:

  • Domain types in packages/domain/opportunity/
  • Field map configuration
  • SalesforceOpportunityService
  • Cancellation deadline helpers (25th rule)
  • Eligibility request creates/reuses Opportunity (Stage Introduction) and links Case (Case.OpportunityId)
  • Order placement reuses Opportunity in Introduction/Ready (otherwise creates new Post Processing)
  • Fulfillment passes OpportunityId to WHMCS and links WHMCS_Service_ID__c back to the Opportunity
  • Cancellation Case creation + Opportunity cancellation field updates (Internet cancellations)

Optional / Future:

  • Read OpportunityId back from WHMCS service custom fields (portal currently relies on Salesforce WHMCS_Service_ID__c for linking)

Frontend Tasks

  • Order tracking page (from Salesforce Order)
  • Service page with cancellation status
  • Cancellation forms (Internet + SIM) with 25th deadline logic