2025-08-23 17:24:37 +09:00
# Portal – Data Model & Mappings
2025-08-27 10:54:05 +09:00
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)
2025-09-09 18:19:54 +09:00
2025-08-27 20:01:46 +09:00
**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`
2025-08-27 10:54:05 +09:00
**SIM**: `SIM_Data_Size__c` , `SIM_Plan_Type__c` , `SIM_Has_Family_Discount__c`
2025-08-27 20:01:46 +09:00
**Edge Cases**: `Is_Default__c` , `Display_Order__c` , `Auto_Add__c` , `VPN_Region__c`
2025-09-09 18:19:54 +09:00
_Note: For complete product setup details, see `SALESFORCE-PRODUCTS.md` _
2025-08-27 10:54:05 +09:00
### Order (6 core + service-specific independent fields)
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
**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)
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
**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:**
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```sql
2025-08-27 20:01:46 +09:00
-- Main Services (Portal_Catalog = true)
2025-08-27 10:54:05 +09:00
"Internet Gold Plan" → Item_Class: "Service" → Monthly billing
"Single Installation" → Item_Class: "Installation" → One-time billing
2025-08-27 20:01:46 +09:00
-- Add-on Services (Portal_Catalog = false, shown as checkboxes)
2025-08-27 10:54:05 +09:00
"Hikari Denwa (Home Phone)" → Item_Class: "Add-on" → Monthly billing
2025-09-09 18:19:54 +09:00
"Weekend Installation" → Item_Class: "Add-on" → One-time billing
2025-08-27 10:54:05 +09:00
"Hikari Denwa Installation" → Item_Class: "Add-on" → One-time billing (auto-added when Denwa selected)
```
**Key Points:**
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
- **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
2025-08-23 17:24:37 +09:00
## Object inventory (what's standard vs custom)
2025-08-27 10:54:05 +09:00
- Salesforce standard
2025-08-23 17:24:37 +09:00
- `Product2` (catalog)
- `Pricebook2` / `PricebookEntry` (pricing)
- `Order` (header)
- `OrderItem` (line)
2025-08-27 10:54:05 +09:00
- `Account` (customer profile and eligibility)
2025-08-23 17:24:37 +09:00
- WHMCS
2025-08-27 10:54:05 +09:00
- 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)
2025-08-27 20:01:46 +09:00
### Product2 Field Reference
2025-08-27 10:54:05 +09:00
2025-09-09 18:19:54 +09:00
_For complete Product2 field definitions, custom fields, and edge case handling, see `SALESFORCE-PRODUCTS.md` _
2025-08-27 10:54:05 +09:00
2025-08-27 20:01:46 +09:00
#### Core Fields Summary
2025-09-09 18:19:54 +09:00
2025-08-27 20:01:46 +09:00
- `StockKeepingUnit` - Product identifier (detailed format: `INTERNET-SILVER-APT-1G` )
2025-09-09 18:19:54 +09:00
- `Product2Categories1__c` - "Internet", "SIM", "VPN", "Other"
2025-08-27 20:01:46 +09:00
- `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
2025-08-27 10:54:05 +09:00
#### Pricing (from PricebookEntry)
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```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:
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
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:
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
- **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:
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
- **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:**
2025-09-09 18:19:54 +09:00
_For complete product definitions with all SKUs, fields, and WHMCS IDs, see `SALESFORCE-PRODUCTS.md` _
2025-08-27 20:01:46 +09:00
2025-08-27 10:54:05 +09:00
```sql
-- Main Service Plans (Portal_Catalog = true, Portal_Accessible = true)
2025-08-27 20:01:46 +09:00
"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
2025-08-27 10:54:05 +09:00
-- 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
2025-09-09 18:19:54 +09:00
Gold: Premium pricing, operator reviews and may adjust configuration
2025-08-27 10:54:05 +09:00
Platinum: Premium pricing + additional fees, operator reviews and may adjust configuration
```
### Order (clean field structure)
#### Core Fields (Required for all orders)
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```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)
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```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)
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```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)
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```sql
-- Customer Selections
VPN_Region__c Picklist -- "USA-SF", "UK-London" (customer chooses region)
```
#### SIM Order Fields (Customer choices + MNP data)
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```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
2025-09-09 18:19:54 +09:00
Porting_FirstName__c Text(255) -- Kanji/Alphabet
2025-08-27 10:54:05 +09:00
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
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```sql
WHMCS_Order_ID__c Number(18,0) -- Set after provisioning
```
#### Billing/Shipping Snapshot (Set on create, not synced)
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```sql
-- Billing Address
BillToContactId Lookup(Contact)
BillToStreet Text(255)
BillToCity Text(40)
BillToState Text(80)
BillToPostalCode Text(20)
BillToCountry Text(80)
2025-09-09 18:19:54 +09:00
-- Shipping Address
2025-08-27 10:54:05 +09:00
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)
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```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
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```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
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```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
2025-09-09 18:19:54 +09:00
WH_Product_ID__c Number(18,0)
2025-08-27 10:54:05 +09:00
-- 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
2025-09-09 18:19:54 +09:00
Internet_Monthly_Price__c Currency
2025-08-27 10:54:05 +09:00
-- SIM Fields
2025-09-09 18:19:54 +09:00
SIM_Data_Size__c Text(50)
2025-08-27 10:54:05 +09:00
SIM_Plan_Type__c Picklist Values: DataOnly, DataSmsVoice, VoiceOnly
2025-09-09 18:19:54 +09:00
SIM_Has_Family_Discount__c Checkbox Default: false
2025-08-27 10:54:05 +09:00
-- VPN Fields
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```
#### Order Object
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```sql
-- Core Fields
Order_Type__c Picklist Values: Internet, SIM, VPN, Other
-- Activation Fields
Activation_Type__c Picklist Values: Immediate, Scheduled
2025-09-09 18:19:54 +09:00
Activation_Scheduled_At__c Datetime
2025-08-27 10:54:05 +09:00
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)
2025-09-09 18:19:54 +09:00
EID__c Text(255) Required for eSIM activation
2025-08-27 10:54:05 +09:00
-- MNP Fields (when applicable)
2025-09-09 18:19:54 +09:00
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)
2025-08-27 10:54:05 +09:00
Porting_Gender__c Picklist Values: Male, Female, Corporate/Other
2025-09-09 18:19:54 +09:00
Porting_DateOfBirth__c Date
2025-08-27 10:54:05 +09:00
-- WHMCS Integration
2025-09-09 18:19:54 +09:00
WHMCS_Order_ID__c Number(18,0)
2025-08-27 10:54:05 +09:00
```
#### OrderItem Object
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```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
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```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
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
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
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```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
2025-09-09 18:19:54 +09:00
List< OrderItem > existing = [SELECT Id FROM OrderItem
WHERE OrderId = :order.Id
2025-08-27 10:54:05 +09:00
AND Product2.SKU__c = 'INTERNET-INSTALL-WEEKEND'];
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
if (existing.isEmpty()) {
Product2 product = [SELECT Id FROM Product2 WHERE SKU__c = 'INTERNET-INSTALL-WEEKEND'];
2025-09-09 18:19:54 +09:00
PricebookEntry pbe = [SELECT Id, UnitPrice FROM PricebookEntry
2025-08-27 10:54:05 +09:00
WHERE Product2Id = :product.Id AND Pricebook2.Name = 'Portal'];
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
INSERT new OrderItem(
OrderId = order.Id,
PricebookEntryId = pbe.Id,
Quantity = 1,
UnitPrice = pbe.UnitPrice
);
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
order.Weekend_Install__c = true;
UPDATE order;
}
} else {
// Remove weekend fee if date changed to weekday
2025-09-09 18:19:54 +09:00
DELETE [SELECT Id FROM OrderItem WHERE OrderId = :order.Id
2025-08-27 10:54:05 +09:00
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
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```apex
// Trigger: After Update on Order
// When: Internet_Plan_Tier__c changes
// 1. Remove old Internet service OrderItem
2025-09-09 18:19:54 +09:00
DELETE [SELECT Id FROM OrderItem
WHERE OrderId = :order.Id
AND Product2.Product2Categories1__c = 'Internet'
2025-08-27 10:54:05 +09:00
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];
2025-09-09 18:19:54 +09:00
PricebookEntry pbe = [SELECT Id, UnitPrice FROM PricebookEntry
2025-08-27 10:54:05 +09:00
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
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```apex
// When: Installation_Type__c changes
// 1. Remove old installation OrderItem
2025-09-09 18:19:54 +09:00
DELETE [SELECT Id FROM OrderItem
WHERE OrderId = :order.Id
AND Product2.Product2Categories1__c = 'Internet'
2025-08-27 10:54:05 +09:00
AND Product2.Item_Class__c = 'Install'];
// 2. Add new installation OrderItem if not null
if (order.Installation_Type__c != null) {
2025-09-09 18:19:54 +09:00
String installSku = 'INTERNET-INSTALL-' +
(order.Installation_Type__c == 'Single' ? 'SINGLE' :
2025-08-27 10:54:05 +09:00
order.Installation_Type__c == '12-Month' ? '12M' : '24M');
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
// Create new installation OrderItem with installSku
}
```
#### Weekend Install Toggle
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```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
2025-09-09 18:19:54 +09:00
DELETE [SELECT Id FROM OrderItem
WHERE OrderId = :order.Id
2025-08-27 10:54:05 +09:00
AND Product2.SKU__c = 'INTERNET-INSTALL-WEEKEND'];
}
```
#### Add-on Field Changes
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```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
2025-09-09 18:19:54 +09:00
DELETE [SELECT Id FROM OrderItem WHERE OrderId = :order.Id
2025-08-27 10:54:05 +09:00
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 {
2025-09-09 18:19:54 +09:00
DELETE [SELECT Id FROM OrderItem WHERE OrderId = :order.Id
2025-08-27 10:54:05 +09:00
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
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
```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;
}
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
// 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;
}
2025-09-09 18:19:54 +09:00
2025-08-27 10:54:05 +09:00
// 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)
2025-09-02 16:09:17 +09:00
### WHMCS AddOrder API (Official Format)
**Required Parameters:**
2025-09-09 18:19:54 +09:00
2025-09-02 16:09:17 +09:00
- `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):**
2025-09-09 18:19:54 +09:00
2025-09-02 16:09:17 +09:00
- `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:**
2025-09-09 18:19:54 +09:00
2025-09-02 16:09:17 +09:00
- `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:**
2025-09-09 18:19:54 +09:00
2025-09-02 16:09:17 +09:00
```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:**
2025-09-09 18:19:54 +09:00
2025-09-02 16:09:17 +09:00
```json
{
"result": "success",
"orderid": 12345,
"serviceids": "67890,67891,67892,67893",
"invoiceid": 0
}
```
2025-08-27 10:54:05 +09:00
## Catalog requirements
2025-09-09 18:19:54 +09:00
_For complete catalog architecture, API endpoints, and frontend implementation, see `PRODUCT-CATALOG-ARCHITECTURE.md` _
2025-08-27 20:01:46 +09:00
2025-08-27 10:54:05 +09:00
- Pricebook: create a `Portal` price book; ensure active `PricebookEntry` for each visible Product2
2025-09-09 18:19:54 +09:00
- API dependencies: `GET /catalog` queries `Product2` fields: Id, Name, StockKeepingUnit, Product2Categories1**c, Portal_Catalog**c, Portal_Accessible\_\_c
2025-08-27 20:01:46 +09:00
- New endpoints: `/catalog/sim/activation-fees` , `/catalog/vpn/activation-fees` , `/catalog/sim/addons` , etc.
2025-09-09 18:19:54 +09:00
- Personalized catalog: `GET /catalog/personalized`
2025-08-27 20:01:46 +09:00
- 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)
2025-08-27 10:54:05 +09:00
## 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):
2025-08-27 20:01:46 +09:00
- `Product2.StockKeepingUnit` , `Product2.Portal_Catalog__c` , `Product2.Portal_Accessible__c` , `Product2.Product2Categories1__c`
2025-08-27 10:54:05 +09:00
- 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`
2025-08-27 20:01:46 +09:00
- `productSKU` (Text) → `Product2.StockKeepingUnit` (PBE lookup)
2025-08-27 10:54:05 +09:00
- `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
2025-08-27 20:01:46 +09:00
- BFF resolves pricing by `Product2.StockKeepingUnit` → `PricebookEntry` and provisioning by `Product2.WH_Product_ID__c` → WHMCS `pid[]`
2025-08-27 10:54:05 +09:00
- Use `SIM` as the sole Product2 category for both eSIM and Physical SIM; `Order_Type__c` retains SIM vs eSIM
2025-08-27 20:01:46 +09:00
- All Product2 visible in portal must have `StockKeepingUnit` , `Portal_Catalog__c = true` , and a `PricebookEntry`