2025-10-08 18:14:12 +09:00
|
|
|
/**
|
|
|
|
|
* SIM Domain - Validation
|
|
|
|
|
*
|
|
|
|
|
* Business validation functions for SIM subscriptions.
|
|
|
|
|
* These functions contain no infrastructure dependencies.
|
|
|
|
|
*/
|
|
|
|
|
|
2025-12-10 15:22:10 +09:00
|
|
|
import type { Subscription } from "../subscriptions/schema.js";
|
2025-10-08 18:14:12 +09:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if a subscription is a SIM service
|
|
|
|
|
*
|
|
|
|
|
* Business rule: A subscription is considered a SIM service if its product name
|
|
|
|
|
* or group name contains "SIM" (case-insensitive).
|
|
|
|
|
*
|
|
|
|
|
* @param subscription - The subscription to check
|
|
|
|
|
* @returns true if this is a SIM subscription
|
|
|
|
|
*/
|
|
|
|
|
export function isSimSubscription(subscription: Subscription): boolean {
|
|
|
|
|
const productName = subscription.productName?.toLowerCase() || "";
|
|
|
|
|
const groupName = subscription.groupName?.toLowerCase() || "";
|
|
|
|
|
|
|
|
|
|
return productName.includes("sim") || groupName.includes("sim");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Extract SIM account identifier from subscription data
|
|
|
|
|
*
|
|
|
|
|
* The SIM account identifier (typically a phone number/MSISDN) can be stored
|
|
|
|
|
* in various places depending on the subscription source and configuration.
|
|
|
|
|
* This function tries multiple locations in priority order.
|
|
|
|
|
*
|
|
|
|
|
* @param subscription - The subscription to extract the account from
|
|
|
|
|
* @returns The SIM account identifier (phone number), or null if not found
|
|
|
|
|
*/
|
|
|
|
|
export function extractSimAccountFromSubscription(
|
|
|
|
|
subscription: Subscription
|
|
|
|
|
): string | null {
|
|
|
|
|
// 1. Try domain field first (most common location)
|
|
|
|
|
if (subscription.domain && subscription.domain.trim()) {
|
|
|
|
|
return subscription.domain.trim();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2. Check custom fields for phone number/MSISDN
|
|
|
|
|
if (subscription.customFields) {
|
|
|
|
|
const account = extractFromCustomFields(subscription.customFields);
|
|
|
|
|
if (account) return account;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3. Check if order number looks like a phone number (10-11 digits)
|
|
|
|
|
if (subscription.orderNumber) {
|
|
|
|
|
const orderNum = subscription.orderNumber.toString();
|
|
|
|
|
if (/^\d{10,11}$/.test(orderNum)) {
|
|
|
|
|
return orderNum;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Extract account from custom fields using known field names
|
|
|
|
|
*
|
|
|
|
|
* WHMCS and other billing systems may store the SIM phone number in various
|
|
|
|
|
* custom field names. This function checks all known variations.
|
|
|
|
|
*
|
|
|
|
|
* @param customFields - The custom fields record to search
|
|
|
|
|
* @returns The SIM account if found, null otherwise
|
|
|
|
|
*/
|
|
|
|
|
function extractFromCustomFields(
|
|
|
|
|
customFields: Record<string, unknown>
|
|
|
|
|
): string | null {
|
|
|
|
|
// Known field names for SIM phone numbers across different WHMCS configurations
|
|
|
|
|
const phoneFields = [
|
|
|
|
|
// Standard field names
|
|
|
|
|
"phone",
|
|
|
|
|
"msisdn",
|
|
|
|
|
"phonenumber",
|
|
|
|
|
"phone_number",
|
|
|
|
|
"mobile",
|
|
|
|
|
"sim_phone",
|
|
|
|
|
|
|
|
|
|
// Title case variations
|
|
|
|
|
"Phone Number",
|
|
|
|
|
"MSISDN",
|
|
|
|
|
"Phone",
|
|
|
|
|
"Mobile",
|
|
|
|
|
"SIM Phone",
|
|
|
|
|
"PhoneNumber",
|
|
|
|
|
|
|
|
|
|
// Additional variations
|
|
|
|
|
"mobile_number",
|
|
|
|
|
"sim_number",
|
|
|
|
|
"account_number",
|
|
|
|
|
"Account Number",
|
|
|
|
|
"SIM Account",
|
|
|
|
|
"Phone Number (SIM)",
|
|
|
|
|
"Mobile Number",
|
|
|
|
|
"SIM Number",
|
|
|
|
|
|
|
|
|
|
// Underscore variations
|
|
|
|
|
"SIM_Number",
|
|
|
|
|
"SIM_Phone_Number",
|
|
|
|
|
"Phone_Number_SIM",
|
|
|
|
|
"Mobile_SIM_Number",
|
|
|
|
|
"SIM_Account_Number",
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (const fieldName of phoneFields) {
|
|
|
|
|
const value = customFields[fieldName];
|
|
|
|
|
if (value !== undefined && value !== null && value !== "") {
|
|
|
|
|
return String(value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Clean SIM account format
|
|
|
|
|
*
|
|
|
|
|
* Removes common formatting characters (hyphens, spaces, parentheses)
|
|
|
|
|
* from phone numbers to get a clean numeric string.
|
|
|
|
|
*
|
|
|
|
|
* @param account - The account string to clean
|
|
|
|
|
* @returns Cleaned account string with only digits
|
|
|
|
|
*/
|
|
|
|
|
export function cleanSimAccount(account: string): string {
|
|
|
|
|
return account.replace(/[-\s()]/g, "");
|
|
|
|
|
}
|
|
|
|
|
|