- Adjusted YAML and JSON files for consistent formatting, including healthcheck commands and package exports. - Enhanced readability in various TypeScript files by standardizing string quotes and improving line breaks. - Updated documentation across multiple files to improve clarity and consistency, including address system and logging levels. - Removed unnecessary package-lock.json from shared package directory to streamline dependencies.
723 lines
29 KiB
Markdown
723 lines
29 KiB
Markdown
# Portal – Data Model & Mappings
|
||
|
||
This document consolidates all required/used fields across Salesforce and WHMCS, plus how the portal consumes them.
|
||
|
||
## Quick Reference: Required Fields Summary
|
||
|
||
### Product2 (7 core + service-specific fields)
|
||
|
||
**Core**: `StockKeepingUnit`, `Product2Categories1__c`, `Portal_Catalog__c`, `Portal_Accessible__c`, `Item_Class__c`, `Billing_Cycle__c`, `WH_Product_ID__c`, `WH_Product_Name__c`
|
||
**Internet**: `Internet_Plan_Tier__c`, `Internet_Offering_Type__c`, `Internet_Monthly_Price__c`
|
||
**SIM**: `SIM_Data_Size__c`, `SIM_Plan_Type__c`, `SIM_Has_Family_Discount__c`
|
||
**Edge Cases**: `Is_Default__c`, `Display_Order__c`, `Auto_Add__c`, `VPN_Region__c`
|
||
|
||
_Note: For complete product setup details, see `SALESFORCE-PRODUCTS.md`_
|
||
|
||
### Order (6 core + service-specific independent fields)
|
||
|
||
**Core**: `AccountId`, `EffectiveDate`, `Status`, `Pricebook2Id`, `Order_Type__c`
|
||
**Activation**: `Activation_Type__c`, `Activation_Scheduled_At__c`, `Activation_Status__c`
|
||
**Internet**: `Internet_Plan_Tier__c`, `Installation_Type__c`, `Weekend_Install__c`, `Access_Mode__c`, `Hikari_Denwa__c`
|
||
**VPN**: `VPN_Region__c`
|
||
**SIM**: `SIM_Type__c`, `EID__c`, `SIM_Voice_Mail__c`, `SIM_Call_Waiting__c` + MNP fields
|
||
**WHMCS**: `WHMCS_Order_ID__c`
|
||
|
||
### OrderItem (2 core + 2 integration fields)
|
||
|
||
**Core**: `OrderId`, `PricebookEntryId`, `Quantity`, `UnitPrice`
|
||
**WHMCS**: `WHMCS_Service_ID__c`, `Billing_Cycle__c`
|
||
|
||
## Order with Add-ons Example
|
||
|
||
When a customer orders "Internet Gold + Hikari Denwa + Weekend Installation":
|
||
|
||
```sql
|
||
-- Order Header
|
||
Order_Type__c: "Internet"
|
||
Internet_Plan_Tier__c: "Gold"
|
||
Installation_Type__c: "Single"
|
||
Weekend_Install__c: true -- Synced from add-on OrderItem
|
||
|
||
-- OrderItems (5 separate items)
|
||
1. Internet Gold Service → SKU: "INTERNET-GOLD" → WH: 188 (monthly)
|
||
2. Internet Installation → SKU: "INTERNET-INSTALL-SINGLE" → WH: 242 (one-time)
|
||
3. Weekend Installation Fee → SKU: "INTERNET-INSTALL-WEEKEND" → WH: 245 (one-time ¥3000)
|
||
4. Hikari Denwa Service → SKU: "INTERNET-ADDON-HOME-PHONE" → WH: 246 (monthly ¥450)
|
||
5. Hikari Denwa Installation → SKU: "INTERNET-ADDON-DENWA-INSTALL" → WH: 247 (one-time)
|
||
```
|
||
|
||
**Complete Product Structure Needed:**
|
||
|
||
```sql
|
||
-- Main Services (Portal_Catalog = true)
|
||
"Internet Gold Plan" → Item_Class: "Service" → Monthly billing
|
||
"Single Installation" → Item_Class: "Installation" → One-time billing
|
||
|
||
-- Add-on Services (Portal_Catalog = false, shown as checkboxes)
|
||
"Hikari Denwa (Home Phone)" → Item_Class: "Add-on" → Monthly billing
|
||
"Weekend Installation" → Item_Class: "Add-on" → One-time billing
|
||
"Hikari Denwa Installation" → Item_Class: "Add-on" → One-time billing (auto-added when Denwa selected)
|
||
```
|
||
|
||
**Key Points:**
|
||
|
||
- **5 OrderItems total** - each service/fee is separate
|
||
- **Automatic dependencies** - selecting Hikari Denwa auto-adds its installation fee
|
||
- **Mixed billing cycles** - services are monthly, installations are one-time
|
||
- **Independent WHMCS products** - each OrderItem maps to different WHMCS Product ID
|
||
|
||
## Object inventory (what's standard vs custom)
|
||
|
||
- Salesforce standard
|
||
- `Product2` (catalog)
|
||
- `Pricebook2` / `PricebookEntry` (pricing)
|
||
- `Order` (header)
|
||
- `OrderItem` (line)
|
||
- `Account` (customer profile and eligibility)
|
||
|
||
- WHMCS
|
||
- Use native User, Client, Order, Invoice, Product (Service). No custom tables.
|
||
|
||
## Salesforce fields (by object)
|
||
|
||
### Account (eligibility and mapping)
|
||
|
||
- Eligibility (used for personalized Internet catalog)
|
||
- `Internet_Eligibility__c` (Picklist)
|
||
- Values (Label = API Name):
|
||
- `Home 1G`
|
||
- `Home 10G`
|
||
- `Apartment 1G`
|
||
- `Apartment 100M`
|
||
- Default behavior: if the field is missing/blank/invalid, the portal treats eligibility as `Home 1G`.
|
||
- Environment variable mapping (so code doesn’t hardcode field API names):
|
||
- `ELIGIBILITY_INTERNET_FIELD` (default: `Internet_Eligibility__c`)
|
||
|
||
- Mapping key
|
||
- `SF_Account_No__c` (Text) used to link portal user ↔ Account (via WHMCS link/signup)
|
||
|
||
### Product2 Field Reference
|
||
|
||
_For complete Product2 field definitions, custom fields, and edge case handling, see `SALESFORCE-PRODUCTS.md`_
|
||
|
||
#### Core Fields Summary
|
||
|
||
- `StockKeepingUnit` - Product identifier (detailed format: `INTERNET-SILVER-APT-1G`)
|
||
- `Product2Categories1__c` - "Internet", "SIM", "VPN", "Other"
|
||
- `Portal_Catalog__c` - Show in main catalog (GET /catalog)
|
||
- `Portal_Accessible__c` - Can be used in orders/OrderItems
|
||
- `Item_Class__c` - "Service", "Installation", "Add-on", "Activation"
|
||
- `WH_Product_ID__c` - WHMCS Product ID
|
||
|
||
#### Pricing (from PricebookEntry)
|
||
|
||
```sql
|
||
-- Pricing comes from PricebookEntry.UnitPrice where Pricebook2Id = '01sTL000008eLVlYAM' (Portal Price Book)
|
||
-- Portal Price Book ID is configurable via PORTAL_PRICEBOOK_ID environment variable
|
||
UnitPrice Currency -- Display price (¥4800, ¥4900, ¥5300)
|
||
```
|
||
|
||
## Add-on Products
|
||
|
||
Add-ons are separate products that customers can select alongside main services. They use the existing product structure with `Item_Class__c = "Add-on"`, `Portal_Catalog__c = false` (hidden from catalog), and `Portal_Accessible__c = true` (can be ordered).
|
||
|
||
### How Add-ons Work:
|
||
|
||
1. **Customer Selection**: Optional add-ons appear as checkboxes (e.g., Hikari Denwa)
|
||
2. **Frontend Logic**: Auto-add dependencies (e.g., Hikari Denwa adds installation fee)
|
||
3. **Salesforce Logic**: Auto-detect conditions and add OrderItems (e.g., weekend installation dates)
|
||
4. **Order Creation**: Each selected/detected add-on creates a separate OrderItem
|
||
5. **Provisioning**: Each add-on provisions as separate WHMCS product
|
||
6. **Billing**: Add-ons have their own pricing and billing cycles
|
||
|
||
### Internet Add-ons:
|
||
|
||
- **Weekend Installation**: Salesforce auto-adds (¥3000) - `INTERNET-INSTALL-WEEKEND` (when installation date is weekend)
|
||
- **Hikari Denwa Service**: Customer checkbox (¥450/month) - `INTERNET-ADDON-HOME-PHONE`
|
||
- **Hikari Denwa Installation**: Frontend auto-adds (one-time) - `INTERNET-ADDON-DENWA-INSTALL`
|
||
|
||
### SIM Add-ons:
|
||
|
||
- **Voice Mail**: Monthly service - `SIM-ADDON-VOICE-MAIL`
|
||
- **Call Waiting**: Monthly service - `SIM-ADDON-CALL-WAITING`
|
||
- **Unlimited Calling**: Monthly service - `SIM-ADDON-UNLIMITED-CALLING`
|
||
|
||
**Product Structure Examples:**
|
||
_For complete product definitions with all SKUs, fields, and WHMCS IDs, see `SALESFORCE-PRODUCTS.md`_
|
||
|
||
```sql
|
||
-- Main Service Plans (Portal_Catalog = true, Portal_Accessible = true)
|
||
"Internet Silver Plan (Apartment 1G)" → SKU: "INTERNET-SILVER-APT-1G" → WH_Product_ID__c: 184
|
||
"Internet Gold Plan (Apartment 1G)" → SKU: "INTERNET-GOLD-APT-1G" → WH_Product_ID__c: 185
|
||
"Internet Platinum Plan (Apartment 1G)" → SKU: "INTERNET-PLATINUM-APT-1G" → WH_Product_ID__c: 186
|
||
|
||
-- Add-on Services (Portal_Catalog = false, Portal_Accessible = true)
|
||
"Weekend Installation" → SKU: "INTERNET-INSTALL-WEEKEND" → WH_Product_ID__c: 245
|
||
"Hikari Denwa (Home Phone)" → SKU: "INTERNET-ADDON-HOME-PHONE" → WH_Product_ID__c: 246
|
||
|
||
-- Customer sees clear messaging:
|
||
Silver: Standard pricing, customer configures access mode
|
||
Gold: Premium pricing, operator reviews and may adjust configuration
|
||
Platinum: Premium pricing + additional fees, operator reviews and may adjust configuration
|
||
```
|
||
|
||
### Order (clean field structure)
|
||
|
||
#### Core Fields (Required for all orders)
|
||
|
||
```sql
|
||
-- Salesforce Standard Fields
|
||
AccountId Lookup(Account) -- Customer account
|
||
EffectiveDate Date -- Order date
|
||
Status Picklist -- "Pending Review", "Approved", "Completed", "Cancelled"
|
||
Pricebook2Id Lookup(Pricebook2) -- Portal pricebook
|
||
OpportunityId Lookup(Opportunity) -- Optional, created by BFF
|
||
|
||
-- Order Classification
|
||
Order_Type__c Picklist -- "Internet", "SIM", "VPN", "Other"
|
||
```
|
||
|
||
#### Activation Fields (All order types)
|
||
|
||
```sql
|
||
Activation_Type__c Picklist -- "Immediate", "Scheduled"
|
||
Activation_Scheduled_At__c Datetime -- When Status = Scheduled
|
||
Activation_Status__c Picklist -- "Not Started", "Activating", "Activated", "Failed"
|
||
```
|
||
|
||
#### Internet Order Fields (Independent fields synced with OrderItems)
|
||
|
||
```sql
|
||
-- Customer/Operator Selections (Independent fields)
|
||
Internet_Plan_Tier__c Picklist -- "Silver", "Gold", "Platinum" (syncs with OrderItems)
|
||
Installation_Type__c Picklist -- "Single", "12-Month", "24-Month" (syncs with OrderItems)
|
||
Weekend_Install__c Checkbox -- Weekend installation add-on (syncs with OrderItems)
|
||
Access_Mode__c Picklist -- "IPoE-BYOR", "IPoE-HGW", "PPPoE" (operator configures)
|
||
|
||
-- Add-on Selections (Customer choices, syncs with OrderItems)
|
||
Hikari_Denwa__c Checkbox -- Customer selected Hikari Denwa service
|
||
```
|
||
|
||
#### VPN Order Fields (Customer selections)
|
||
|
||
```sql
|
||
-- Customer Selections
|
||
VPN_Region__c Picklist -- "USA-SF", "UK-London" (customer chooses region)
|
||
```
|
||
|
||
#### SIM Order Fields (Customer choices + MNP data)
|
||
|
||
```sql
|
||
-- SIM Configuration (plan type and data size come from selected Product2)
|
||
SIM_Type__c Picklist -- "eSIM", "Physical SIM" (customer choice)
|
||
EID__c Text(255) -- Required when SIM_Type__c = "eSIM"
|
||
|
||
-- Add-on Selections (Customer choices, syncs with OrderItems)
|
||
SIM_Voice_Mail__c Checkbox -- Customer selected Voice Mail add-on
|
||
SIM_Call_Waiting__c Checkbox -- Customer selected Call Waiting add-on
|
||
|
||
|
||
-- MNP/Porting (when MNP_Application__c = true)
|
||
MNP_Application__c Checkbox -- Customer wants to port number
|
||
MNP_Reservation_Number__c Text(10) -- 10 digits numeric
|
||
MNP_Expiry_Date__c Date -- MNP expiry date
|
||
MNP_Phone_Number__c Text(11) -- 11 digits, no hyphens
|
||
MVNO_Account_Number__c Text(255) -- Optional
|
||
Porting_LastName__c Text(255) -- Kanji/Alphabet
|
||
Porting_FirstName__c Text(255) -- Kanji/Alphabet
|
||
Porting_LastName_Katakana__c Text(255) -- Katakana
|
||
Porting_FirstName_Katakana__c Text(255) -- Katakana
|
||
Porting_Gender__c Picklist -- "Male", "Female", "Corporate/Other"
|
||
Porting_DateOfBirth__c Date -- YYYY/MM/DD
|
||
```
|
||
|
||
#### WHMCS Integration Fields
|
||
|
||
```sql
|
||
WHMCS_Order_ID__c Number(18,0) -- Set after provisioning
|
||
```
|
||
|
||
#### Billing/Shipping Snapshot (Set on create, not synced)
|
||
|
||
```sql
|
||
-- Billing Address
|
||
BillToContactId Lookup(Contact)
|
||
BillToStreet Text(255)
|
||
BillToCity Text(40)
|
||
BillToState Text(80)
|
||
BillToPostalCode Text(20)
|
||
BillToCountry Text(80)
|
||
|
||
-- Shipping Address
|
||
ShipToContactId Lookup(Contact)
|
||
ShipToStreet Text(255)
|
||
ShipToCity Text(40)
|
||
ShipToState Text(80)
|
||
ShipToPostalCode Text(20)
|
||
ShipToCountry Text(80)
|
||
```
|
||
|
||
### OrderItem (clean field structure)
|
||
|
||
#### Core Fields (Required for all order items)
|
||
|
||
```sql
|
||
-- Salesforce Standard Fields
|
||
OrderId Lookup(Order) -- Parent order
|
||
PricebookEntryId Lookup(PricebookEntry) -- Product + pricing
|
||
Quantity Number(18,2) -- Usually 1
|
||
UnitPrice Currency -- Price at time of order
|
||
```
|
||
|
||
#### WHMCS Integration Fields
|
||
|
||
```sql
|
||
-- Provisioning
|
||
WHMCS_Service_ID__c Number(18,0) -- Set after provisioning
|
||
Billing_Cycle__c Picklist -- "Monthly", "Annually", "One-time"
|
||
```
|
||
|
||
**Note**: `WH_Product_ID__c` is stored on Product2, but operator can override it on OrderItem during review for Gold/Platinum plans.
|
||
|
||
## Salesforce Setup Checklist
|
||
|
||
### Custom Fields to Create
|
||
|
||
#### Product2 Object
|
||
|
||
```sql
|
||
-- Core Fields (All Products)
|
||
StockKeepingUnit Text(255) External ID, Unique (standard Salesforce field)
|
||
Product2Categories1__c Picklist Values: Internet, SIM, VPN, Other
|
||
Portal_Catalog__c Checkbox Default: false
|
||
Portal_Accessible__c Checkbox Default: true
|
||
Item_Class__c Picklist Values: Service, Installation, Add-on, Activation
|
||
WH_Product_ID__c Number(18,0)
|
||
|
||
-- Internet Fields
|
||
Internet_Plan_Tier__c Picklist Values: Silver, Gold, Platinum
|
||
Internet_Offering_Type__c Picklist Values: Home 1G, Home 10G, Apartment 1G, Apartment 100M
|
||
Internet_Monthly_Price__c Currency
|
||
|
||
|
||
-- SIM Fields
|
||
SIM_Data_Size__c Text(50)
|
||
SIM_Plan_Type__c Picklist Values: DataOnly, DataSmsVoice, VoiceOnly
|
||
SIM_Has_Family_Discount__c Checkbox Default: false
|
||
|
||
-- VPN Fields
|
||
|
||
```
|
||
|
||
#### Order Object
|
||
|
||
```sql
|
||
-- Core Fields
|
||
Order_Type__c Picklist Values: Internet, SIM, VPN, Other
|
||
|
||
-- Activation Fields
|
||
Activation_Type__c Picklist Values: Immediate, Scheduled
|
||
Activation_Scheduled_At__c Datetime
|
||
Activation_Status__c Picklist Values: Not Started, Activating, Activated, Failed
|
||
|
||
-- Internet Fields (Independent fields synced with OrderItems)
|
||
Internet_Plan_Tier__c Picklist Values: Silver, Gold, Platinum
|
||
Installation_Type__c Picklist Values: Single, 12-Month, 24-Month
|
||
Weekend_Install__c Checkbox Weekend installation add-on
|
||
Access_Mode__c Picklist Values: IPoE-BYOR, IPoE-HGW, PPPoE (operator sets)
|
||
|
||
-- VPN Fields (Independent fields)
|
||
VPN_Region__c Picklist Values: USA-SF, UK-London (customer chooses)
|
||
|
||
-- SIM Fields (Customer choices only - plan details come from Product2)
|
||
SIM_Type__c Picklist Values: eSIM, Physical SIM (customer chooses format)
|
||
EID__c Text(255) Required for eSIM activation
|
||
|
||
-- MNP Fields (when applicable)
|
||
MNP_Application__c Checkbox
|
||
MNP_Reservation_Number__c Text(10)
|
||
MNP_Expiry_Date__c Date
|
||
MNP_Phone_Number__c Text(11)
|
||
MVNO_Account_Number__c Text(255)
|
||
Porting_LastName__c Text(255)
|
||
Porting_FirstName__c Text(255)
|
||
Porting_LastName_Katakana__c Text(255)
|
||
Porting_FirstName_Katakana__c Text(255)
|
||
Porting_Gender__c Picklist Values: Male, Female, Corporate/Other
|
||
Porting_DateOfBirth__c Date
|
||
|
||
-- WHMCS Integration
|
||
WHMCS_Order_ID__c Number(18,0)
|
||
|
||
|
||
```
|
||
|
||
#### OrderItem Object
|
||
|
||
```sql
|
||
-- WHMCS Integration Fields
|
||
WHMCS_Service_ID__c Number(18,0) Set after provisioning
|
||
Billing_Cycle__c Picklist Values: Monthly, Annually, One-time
|
||
```
|
||
|
||
#### Account Object
|
||
|
||
```sql
|
||
-- Portal Integration Fields
|
||
Internet_Eligibility__c Picklist Values: Home 1G, Home 10G, Apartment 1G, Apartment 100M
|
||
SF_Account_No__c Text(255) External ID, Unique (Customer Number)
|
||
```
|
||
|
||
## Salesforce Sync Flow: Order Fields ↔ OrderItems
|
||
|
||
### Overview
|
||
|
||
Independent fields on Order are synced with OrderItems using Salesforce Flow. When operators change Order fields, Flow automatically adds/removes/updates OrderItems. When OrderItems change, Flow updates Order fields.
|
||
|
||
### Weekend Installation Auto-Detection
|
||
|
||
```apex
|
||
// Trigger: After Insert, After Update on Order
|
||
// When: Installation_Scheduled_Date__c changes
|
||
|
||
Date installDate = order.Installation_Scheduled_Date__c;
|
||
String dayOfWeek = installDate.format('E'); // 'Sat' or 'Sun' for weekends
|
||
|
||
if (dayOfWeek == 'Sat' || dayOfWeek == 'Sun') {
|
||
// Add weekend installation fee if not exists
|
||
List<OrderItem> existing = [SELECT Id FROM OrderItem
|
||
WHERE OrderId = :order.Id
|
||
AND Product2.SKU__c = 'INTERNET-INSTALL-WEEKEND'];
|
||
|
||
if (existing.isEmpty()) {
|
||
Product2 product = [SELECT Id FROM Product2 WHERE SKU__c = 'INTERNET-INSTALL-WEEKEND'];
|
||
PricebookEntry pbe = [SELECT Id, UnitPrice FROM PricebookEntry
|
||
WHERE Product2Id = :product.Id AND Pricebook2.Name = 'Portal'];
|
||
|
||
INSERT new OrderItem(
|
||
OrderId = order.Id,
|
||
PricebookEntryId = pbe.Id,
|
||
Quantity = 1,
|
||
UnitPrice = pbe.UnitPrice
|
||
);
|
||
|
||
order.Weekend_Install__c = true;
|
||
UPDATE order;
|
||
}
|
||
} else {
|
||
// Remove weekend fee if date changed to weekday
|
||
DELETE [SELECT Id FROM OrderItem WHERE OrderId = :order.Id
|
||
AND Product2.SKU__c = 'INTERNET-INSTALL-WEEKEND'];
|
||
order.Weekend_Install__c = false;
|
||
UPDATE order;
|
||
}
|
||
```
|
||
|
||
### Flow 1: Order Fields → OrderItems (When operator changes Order fields)
|
||
|
||
#### Internet Plan Tier Change
|
||
|
||
```apex
|
||
// Trigger: After Update on Order
|
||
// When: Internet_Plan_Tier__c changes
|
||
|
||
// 1. Remove old Internet service OrderItem
|
||
DELETE [SELECT Id FROM OrderItem
|
||
WHERE OrderId = :order.Id
|
||
AND Product2.Product2Categories1__c = 'Internet'
|
||
AND Product2.Item_Class__c = 'Service'];
|
||
|
||
// 2. Add new Internet service OrderItem
|
||
String newSku = 'INTERNET-' + order.Internet_Plan_Tier__c.toUpperCase();
|
||
Product2 newProduct = [SELECT Id FROM Product2 WHERE SKU__c = :newSku LIMIT 1];
|
||
PricebookEntry pbe = [SELECT Id, UnitPrice FROM PricebookEntry
|
||
WHERE Product2Id = :newProduct.Id AND Pricebook2.Name = 'Portal' LIMIT 1];
|
||
|
||
OrderItem newItem = new OrderItem(
|
||
OrderId = order.Id,
|
||
PricebookEntryId = pbe.Id,
|
||
Quantity = 1,
|
||
UnitPrice = pbe.UnitPrice
|
||
);
|
||
INSERT newItem;
|
||
```
|
||
|
||
#### Installation Type Change
|
||
|
||
```apex
|
||
// When: Installation_Type__c changes
|
||
|
||
// 1. Remove old installation OrderItem
|
||
DELETE [SELECT Id FROM OrderItem
|
||
WHERE OrderId = :order.Id
|
||
AND Product2.Product2Categories1__c = 'Internet'
|
||
AND Product2.Item_Class__c = 'Install'];
|
||
|
||
// 2. Add new installation OrderItem if not null
|
||
if (order.Installation_Type__c != null) {
|
||
String installSku = 'INTERNET-INSTALL-' +
|
||
(order.Installation_Type__c == 'Single' ? 'SINGLE' :
|
||
order.Installation_Type__c == '12-Month' ? '12M' : '24M');
|
||
|
||
// Create new installation OrderItem with installSku
|
||
}
|
||
```
|
||
|
||
#### Weekend Install Toggle
|
||
|
||
```apex
|
||
// When: Weekend_Install__c changes
|
||
|
||
if (order.Weekend_Install__c == true && oldOrder.Weekend_Install__c == false) {
|
||
// Add weekend installation OrderItem
|
||
// SKU: 'INTERNET-INSTALL-WEEKEND'
|
||
} else if (order.Weekend_Install__c == false && oldOrder.Weekend_Install__c == true) {
|
||
// Remove weekend installation OrderItem
|
||
DELETE [SELECT Id FROM OrderItem
|
||
WHERE OrderId = :order.Id
|
||
AND Product2.SKU__c = 'INTERNET-INSTALL-WEEKEND'];
|
||
}
|
||
```
|
||
|
||
#### Add-on Field Changes
|
||
|
||
```apex
|
||
// When: Hikari_Denwa__c changes
|
||
if (order.Hikari_Denwa__c == true && oldOrder.Hikari_Denwa__c == false) {
|
||
// Add Hikari Denwa service and installation OrderItems
|
||
INSERT new OrderItem(Product2.SKU__c = 'INTERNET-ADDON-HOME-PHONE');
|
||
INSERT new OrderItem(Product2.SKU__c = 'INTERNET-ADDON-DENWA-INSTALL');
|
||
} else if (order.Hikari_Denwa__c == false && oldOrder.Hikari_Denwa__c == true) {
|
||
// Remove Hikari Denwa OrderItems
|
||
DELETE [SELECT Id FROM OrderItem WHERE OrderId = :order.Id
|
||
AND Product2.SKU__c IN ('INTERNET-ADDON-HOME-PHONE', 'INTERNET-ADDON-DENWA-INSTALL')];
|
||
}
|
||
|
||
// When: SIM add-on fields change
|
||
if (order.SIM_Voice_Mail__c != oldOrder.SIM_Voice_Mail__c) {
|
||
if (order.SIM_Voice_Mail__c) {
|
||
INSERT new OrderItem(Product2.SKU__c = 'SIM-ADDON-VOICE-MAIL');
|
||
} else {
|
||
DELETE [SELECT Id FROM OrderItem WHERE OrderId = :order.Id
|
||
AND Product2.SKU__c = 'SIM-ADDON-VOICE-MAIL'];
|
||
}
|
||
}
|
||
|
||
// Similar logic for SIM_Call_Waiting__c
|
||
```
|
||
|
||
### Flow 2: OrderItems → Order Fields (When OrderItems change)
|
||
|
||
#### Sync Order Fields from OrderItems
|
||
|
||
```apex
|
||
// Trigger: After Insert, After Update, After Delete on OrderItem
|
||
// Purpose: Keep Order fields in sync with OrderItems
|
||
|
||
// Get all OrderItems for this Order
|
||
List<OrderItem> items = [SELECT Product2.Internet_Plan_Tier__c, Product2.SKU__c,
|
||
Product2.Item_Class__c, Product2.Product2Categories1__c
|
||
FROM OrderItem WHERE OrderId = :orderId];
|
||
|
||
Order orderToUpdate = new Order(Id = orderId);
|
||
|
||
// Sync Internet fields
|
||
for (OrderItem item : items) {
|
||
if (item.Product2.Product2Categories1__c == 'Internet' && item.Product2.Item_Class__c == 'Service') {
|
||
orderToUpdate.Internet_Plan_Tier__c = item.Product2.Internet_Plan_Tier__c;
|
||
}
|
||
if (item.Product2.Product2Categories1__c == 'Internet' && item.Product2.Item_Class__c == 'Installation') {
|
||
if (item.Product2.SKU__c.contains('SINGLE')) orderToUpdate.Installation_Type__c = 'Single';
|
||
else if (item.Product2.SKU__c.contains('12M')) orderToUpdate.Installation_Type__c = '12-Month';
|
||
else if (item.Product2.SKU__c.contains('24M')) orderToUpdate.Installation_Type__c = '24-Month';
|
||
}
|
||
if (item.Product2.SKU__c == 'INTERNET-INSTALL-WEEKEND') {
|
||
orderToUpdate.Weekend_Install__c = true;
|
||
}
|
||
if (item.Product2.SKU__c == 'INTERNET-ADDON-HOME-PHONE') {
|
||
orderToUpdate.Hikari_Denwa__c = true;
|
||
}
|
||
|
||
// SIM add-on sync
|
||
if (item.Product2.SKU__c == 'SIM-ADDON-VOICE-MAIL') {
|
||
orderToUpdate.SIM_Voice_Mail__c = true;
|
||
}
|
||
if (item.Product2.SKU__c == 'SIM-ADDON-CALL-WAITING') {
|
||
orderToUpdate.SIM_Call_Waiting__c = true;
|
||
}
|
||
|
||
|
||
// VPN fields: Only VPN_Region__c is stored on Order (customer selection)
|
||
}
|
||
|
||
// Set defaults if no items found
|
||
if (noInternetService) orderToUpdate.Internet_Plan_Tier__c = null;
|
||
if (noInstallation) orderToUpdate.Installation_Type__c = null;
|
||
if (noWeekendInstall) orderToUpdate.Weekend_Install__c = false;
|
||
if (noHikariDenwa) orderToUpdate.Hikari_Denwa__c = false;
|
||
if (noSIMVoiceMail) orderToUpdate.SIM_Voice_Mail__c = false;
|
||
if (noSIMCallWaiting) orderToUpdate.SIM_Call_Waiting__c = false;
|
||
|
||
|
||
UPDATE orderToUpdate;
|
||
```
|
||
|
||
## WHMCS fields/IDs used
|
||
|
||
- Users & Clients (created/linked at signup)
|
||
- User: `firstname`, `lastname`, `email`, `password`
|
||
- Client: `firstname`, `lastname`, `email`, optional `phonenumber`, `companyname`
|
||
- Address: `address1`, `address2`, `city`, `state`, `postcode`, `country`
|
||
- Custom field: `CustomerNumber` (maps to Salesforce Account `SF_Account_No__c`)
|
||
- Link: User ↔ Client recorded in portal mapping table
|
||
|
||
- Invoices & PayMethods
|
||
- GetInvoices (by `clientid`) surfaced in portal
|
||
- GetPayMethods used to gate checkout (must have a method on file)
|
||
- SSO links used to open invoice/payment-methods UI in WHMCS
|
||
|
||
- Client linking in portal
|
||
- Portal mapping stores: `userId`, `whmcsClientId`, `sfAccountId`
|
||
- Product IDs (pid) used in AddOrder:
|
||
- Internet (by dwelling/speed): Home 1G SILV=181, GOLD=182, PLAT=183; APT 1G SILV=184, GOLD=185, PLAT=186; APT 100M SILV=187, GOLD=188, PLAT=189
|
||
- Installation: Single=242, 12M=243, 24M=244
|
||
- VPN: USA=33, UK=54, Activation=37
|
||
- SIM/eSIM: see mapping table above (e.g., Data-only 5GB=97, Data+Voice 10GB=216, Voice-only=142)
|
||
|
||
### WHMCS AddOrder API (Official Format)
|
||
|
||
**Required Parameters:**
|
||
|
||
- `clientid` (int) – WHMCS client ID resolved from `Order.AccountId` via portal mapping
|
||
- `paymentmethod` (string) – Payment method (e.g., "mailin", "paypal") - **Required by WHMCS API**
|
||
|
||
**Product Arrays (Official WHMCS Format):**
|
||
|
||
- `pid[]` (string[]) – Array of WHMCS product IDs from `Product2.WH_Product_ID__c`
|
||
- `billingcycle[]` (string[]) – Array of billing cycles from `Product2.Billing_Cycle__c`
|
||
- `qty[]` (int[]) – Array of quantities from `OrderItem.Quantity`
|
||
|
||
**Optional Parameters:**
|
||
|
||
- `promocode` (string) – Promotion code
|
||
- `noinvoice` (bool) – Suppress invoice creation (true for provisioning)
|
||
- `noemail` (bool) – Suppress order confirmation email (true for provisioning)
|
||
- `configoptions[]` (string[]) – Base64 encoded serialized arrays (if needed)
|
||
- `customfields[]` (string[]) – Base64 encoded serialized arrays (if needed)
|
||
|
||
**Example Request:**
|
||
|
||
```json
|
||
{
|
||
"clientid": 1,
|
||
"paymentmethod": "mailin",
|
||
"pid": ["185", "242", "246", "247"],
|
||
"billingcycle": ["monthly", "onetime", "monthly", "onetime"],
|
||
"qty": [1, 1, 1, 1],
|
||
"noinvoice": true,
|
||
"noemail": true
|
||
}
|
||
```
|
||
|
||
**Response:**
|
||
|
||
```json
|
||
{
|
||
"result": "success",
|
||
"orderid": 12345,
|
||
"serviceids": "67890,67891,67892,67893",
|
||
"invoiceid": 0
|
||
}
|
||
```
|
||
|
||
## Catalog requirements
|
||
|
||
_For complete catalog architecture, API endpoints, and frontend implementation, see `PRODUCT-CATALOG-ARCHITECTURE.md`_
|
||
|
||
- Pricebook: create a `Portal` price book; ensure active `PricebookEntry` for each visible Product2
|
||
- API dependencies: `GET /catalog` queries `Product2` fields: Id, Name, StockKeepingUnit, Product2Categories1**c, Portal_Catalog**c, Portal_Accessible\_\_c
|
||
- New endpoints: `/catalog/sim/activation-fees`, `/catalog/vpn/activation-fees`, `/catalog/sim/addons`, etc.
|
||
- Personalized catalog: `GET /catalog/personalized`
|
||
- Filters by consolidated offering: include Product2 where `Internet_Offering_Type__c` equals `Account.Internet_Eligibility__c` (fallback to Home 1G when Account field missing/invalid)
|
||
|
||
## Enablement & permissions (Salesforce)
|
||
|
||
- Enable Products and Price Books in the org (Setup → Product Settings)
|
||
- Integration user (Named Credential/Connected App user) minimum permissions:
|
||
- Objects (Read): `Product2`, `Pricebook2`, `PricebookEntry`, `Order`, `OrderItem`, `Account`
|
||
- Fields (Readable):
|
||
- `Product2.StockKeepingUnit`, `Product2.Portal_Catalog__c`, `Product2.Portal_Accessible__c`, `Product2.Product2Categories1__c`
|
||
- Optional display: `Product2.Portal_Description__c`, `Product2.Portal_Feature_Bullets__c`, `Product2.Portal_Hero_Image_URL__c`, `Product2.Portal_Tags__c`, `Product2.Portal_Sort_Order__c`, `Product2.Portal_Valid_From__c`, `Product2.Portal_Valid_Until__c`
|
||
- Optional eligibility: `Product2.Portal_Eligibility_Dwelling__c`, `Product2.Portal_Eligibility_Speed__c`, `Product2.Portal_Eligibility_Region__c`
|
||
- Account eligibility fields per env: dwelling/speed
|
||
- Order custom fields listed above (Type/Activation/Internet/SIM/MNP)
|
||
- OrderItem custom fields: `ConfigOptions_JSON__c`
|
||
|
||
## Portal field mapping reference (source-of-truth → target)
|
||
|
||
Activation (Portal → Salesforce)
|
||
|
||
- `activationType` (Immediate | Scheduled) → `Order.Activation_Type__c`
|
||
- `activationScheduledAt` (Datetime) → `Order.Activation_Scheduled_At__c`
|
||
|
||
Address (Portal → WHMCS/Order snapshot)
|
||
|
||
- `street` → `WHMCS.Client.address1`; `Order.BillToStreet`
|
||
- `addressLine2` → `WHMCS.Client.address2`
|
||
- `city` → `WHMCS.Client.city`; `Order.BillToCity`
|
||
- `state` → `WHMCS.Client.state`; `Order.BillToState`
|
||
- `postalCode` → `WHMCS.Client.postcode`; `Order.BillToPostalCode`
|
||
- `country` (ISO 2) → `WHMCS.Client.country`; `Order.BillToCountry`
|
||
|
||
Checkout (Portal → Salesforce/WHMCS)
|
||
|
||
- `billingCycle` (UI concept only) → derived server-side from SKU class; WHMCS `billingcycle`
|
||
- `productSKU` (Text) → `Product2.StockKeepingUnit` (PBE lookup)
|
||
- `promoCode` (Text) → WHMCS `promocode`
|
||
- `quantity` (Number) → `OrderItem.Quantity` (validated against `Product2.Portal_Max_Quantity__c`)
|
||
|
||
Internet (Portal → Salesforce)
|
||
|
||
- `accessMode` (IPoE‑HGW | IPoE‑BYOR | PPPoE) → `Order.Access_Mode__c`
|
||
- `installmentPlan` (One-time | 12-Month | 24-Month) → `Order.Installment_Plan__c`
|
||
- `planTier` (Platinum | Gold | Silver) → `Order.Internet_Plan_Tier__c` (derived from SKU)
|
||
- `serviceSpeed` (Text) → `Order.Service_Speed__c`
|
||
- `weekendInstall` (Checkbox) → `Order.Weekend_Install__c`
|
||
- `internetOffering` (Picklist) → `Order.Internet_Offering_Type__c` (defaults from Account when not provided)
|
||
- Also set from product on selection: `Order.Internet_Offering_Type__c = Product2.Portal_Internet_Offering_Type__c`
|
||
|
||
VPN (Portal → Salesforce)
|
||
|
||
- `vpnRegion` (Picklist) → `Order.VPN_Region__c`
|
||
- (optional) `vpnType` (Picklist) → `Order.VPN_Type__c`
|
||
|
||
SIM / eSIM (Portal → Salesforce)
|
||
|
||
- `simType` (eSIM | Physical SIM) → `Order.SIM_Type__c`
|
||
- `eid` (Text) → `Order.EID__c` (required when `SIM_Type__c = eSIM`)
|
||
- Porting (all optional unless flow requires):
|
||
- `mnpApplication` → `Order.MNP_Application__c`
|
||
- `mnpReservationNumber` → `Order.MNP_Reservation_Number__c`
|
||
- `mnpExpiryDate` → `Order.MNP_Expiry_Date__c`
|
||
- `mnpPhoneNumber` → `Order.MNP_Phone_Number__c`
|
||
- `mvnoAccountNumber` → `Order.MVNO_Account_Number__c`
|
||
- `portingDob` → `Order.Porting_DateOfBirth__c`
|
||
- `portingFirstNameKanji` → `Order.Porting_FirstName_Kanji__c`
|
||
- `portingLastNameKanji` → `Order.Porting_LastName_Kanji__c`
|
||
- `portingFirstNameKatakana` → `Order.Porting_FirstName_Katakana__c`
|
||
- `portingLastNameKatakana` → `Order.Porting_LastName_Katakana__c`
|
||
- `portingGender` (Male | Female | Corporate/Other) → `Order.Porting_Gender__c`
|
||
|
||
Signup (Portal → WHMCS; plus SF mapping)
|
||
|
||
- `email`, `firstName`, `lastName`, `password` → WHMCS User + Client
|
||
- `company` → `WHMCS.Client.companyname` (optional)
|
||
- `phone` → `WHMCS.Client.phonenumber` (optional)
|
||
- `customerNumber` (Salesforce Account number) → `WHMCS.Client.customfields.CustomerNumber` → BFF links to Salesforce `Account.SF_Account_No__c`
|
||
|
||
## Notes
|
||
|
||
- BFF resolves pricing by `Product2.StockKeepingUnit` → `PricebookEntry` and provisioning by `Product2.WH_Product_ID__c` → WHMCS `pid[]`
|
||
- Use `SIM` as the sole Product2 category for both eSIM and Physical SIM; `Order_Type__c` retains SIM vs eSIM
|
||
- All Product2 visible in portal must have `StockKeepingUnit`, `Portal_Catalog__c = true`, and a `PricebookEntry`
|