barsa 7c929eb4dc Update Customer Portal Documentation and Remove Deprecated Files
- Streamlined the README.md for clarity and conciseness.
- Deleted outdated documentation files related to Freebit SIM management, SIM management API data flow, and various architectural guides to reduce clutter and improve maintainability.
- Updated the last modified date in the README to reflect the latest changes.
2025-12-23 15:43:36 +09:00

723 lines
29 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 doesnt 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` (IPoEHGW | IPoEBYOR | 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`