2025-10-08 10:33:33 +09:00
|
|
|
/**
|
2025-10-08 11:11:05 +09:00
|
|
|
* Orders Domain - Salesforce Provider Mapper
|
2025-10-08 10:33:33 +09:00
|
|
|
*
|
2025-10-08 11:11:05 +09:00
|
|
|
* Transforms Salesforce Order and OrderItem records into domain contracts.
|
2025-10-08 10:33:33 +09:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import type {
|
|
|
|
|
OrderDetails,
|
|
|
|
|
OrderItemDetails,
|
|
|
|
|
OrderItemSummary,
|
|
|
|
|
OrderSummary,
|
2025-10-08 18:24:21 +09:00
|
|
|
} from "../../contract.js";
|
|
|
|
|
import { orderDetailsSchema, orderSummarySchema, orderItemDetailsSchema } from "../../schema.js";
|
2025-10-08 10:33:33 +09:00
|
|
|
import type {
|
|
|
|
|
SalesforceOrderItemRecord,
|
|
|
|
|
SalesforceOrderRecord,
|
2025-10-08 18:14:12 +09:00
|
|
|
} from "./raw.types.js";
|
2025-10-08 10:33:33 +09:00
|
|
|
|
|
|
|
|
/**
|
2025-10-08 11:11:05 +09:00
|
|
|
* Transform a Salesforce OrderItem record into domain details + summary.
|
2025-10-08 10:33:33 +09:00
|
|
|
*/
|
|
|
|
|
export function transformSalesforceOrderItem(
|
2025-10-08 11:11:05 +09:00
|
|
|
record: SalesforceOrderItemRecord
|
2025-10-08 10:33:33 +09:00
|
|
|
): { details: OrderItemDetails; summary: OrderItemSummary } {
|
2025-10-08 13:46:23 +09:00
|
|
|
// PricebookEntry is unknown to avoid circular dependencies between domains
|
|
|
|
|
const pricebookEntry = record.PricebookEntry as Record<string, any> | null | undefined;
|
|
|
|
|
const product = pricebookEntry?.Product2 as Record<string, any> | undefined;
|
2025-10-08 10:33:33 +09:00
|
|
|
|
|
|
|
|
const details = orderItemDetailsSchema.parse({
|
|
|
|
|
id: record.Id,
|
|
|
|
|
orderId: record.OrderId ?? "",
|
|
|
|
|
quantity: normalizeQuantity(record.Quantity),
|
|
|
|
|
unitPrice: coerceNumber(record.UnitPrice),
|
|
|
|
|
totalPrice: coerceNumber(record.TotalPrice),
|
2025-10-08 11:11:05 +09:00
|
|
|
billingCycle: record.Billing_Cycle__c ?? undefined,
|
2025-10-08 10:33:33 +09:00
|
|
|
product: product
|
|
|
|
|
? {
|
|
|
|
|
id: product.Id ?? undefined,
|
2025-10-08 11:11:05 +09:00
|
|
|
name: product.Name ?? undefined,
|
|
|
|
|
sku: product.StockKeepingUnit ?? undefined,
|
|
|
|
|
itemClass: product.Item_Class__c ?? undefined,
|
|
|
|
|
whmcsProductId: product.WH_Product_ID__c ? String(product.WH_Product_ID__c) : undefined,
|
|
|
|
|
internetOfferingType: product.Internet_Offering_Type__c ?? undefined,
|
|
|
|
|
internetPlanTier: product.Internet_Plan_Tier__c ?? undefined,
|
|
|
|
|
vpnRegion: product.VPN_Region__c ?? undefined,
|
2025-10-08 10:33:33 +09:00
|
|
|
}
|
|
|
|
|
: undefined,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
details,
|
|
|
|
|
summary: {
|
|
|
|
|
productName: details.product?.name,
|
|
|
|
|
name: details.product?.name,
|
|
|
|
|
sku: details.product?.sku,
|
|
|
|
|
status: undefined,
|
|
|
|
|
billingCycle: details.billingCycle,
|
|
|
|
|
itemClass: details.product?.itemClass,
|
|
|
|
|
quantity: details.quantity,
|
|
|
|
|
unitPrice: details.unitPrice,
|
|
|
|
|
totalPrice: details.totalPrice,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Transform a Salesforce Order record (with associated OrderItems) into domain OrderDetails.
|
|
|
|
|
*/
|
|
|
|
|
export function transformSalesforceOrderDetails(
|
|
|
|
|
order: SalesforceOrderRecord,
|
2025-10-08 11:11:05 +09:00
|
|
|
itemRecords: SalesforceOrderItemRecord[]
|
2025-10-08 10:33:33 +09:00
|
|
|
): OrderDetails {
|
|
|
|
|
const transformedItems = itemRecords.map(record =>
|
2025-10-08 11:11:05 +09:00
|
|
|
transformSalesforceOrderItem(record)
|
2025-10-08 10:33:33 +09:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const items = transformedItems.map(item => item.details);
|
|
|
|
|
const itemsSummary = transformedItems.map(item => item.summary);
|
|
|
|
|
|
2025-10-08 11:11:05 +09:00
|
|
|
const summary = buildOrderSummary(order, itemsSummary);
|
2025-10-08 10:33:33 +09:00
|
|
|
|
|
|
|
|
return orderDetailsSchema.parse({
|
|
|
|
|
...summary,
|
|
|
|
|
accountId: order.AccountId ?? undefined,
|
|
|
|
|
accountName: typeof order.Account?.Name === "string" ? order.Account.Name : undefined,
|
|
|
|
|
pricebook2Id: order.Pricebook2Id ?? undefined,
|
2025-10-08 11:11:05 +09:00
|
|
|
activationType: order.Activation_Type__c ?? undefined,
|
2025-10-08 10:33:33 +09:00
|
|
|
activationStatus: summary.activationStatus,
|
2025-10-08 11:11:05 +09:00
|
|
|
activationScheduledAt: order.Activation_Scheduled_At__c ?? undefined,
|
|
|
|
|
activationErrorCode: order.Activation_Error_Code__c ?? undefined,
|
|
|
|
|
activationErrorMessage: order.Activation_Error_Message__c ?? undefined,
|
2025-10-08 10:33:33 +09:00
|
|
|
activatedDate: typeof order.ActivatedDate === "string" ? order.ActivatedDate : undefined,
|
|
|
|
|
items,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Transform a Salesforce Order record (with optional OrderItems) into domain OrderSummary.
|
|
|
|
|
*/
|
|
|
|
|
export function transformSalesforceOrderSummary(
|
|
|
|
|
order: SalesforceOrderRecord,
|
2025-10-08 11:11:05 +09:00
|
|
|
itemRecords: SalesforceOrderItemRecord[]
|
2025-10-08 10:33:33 +09:00
|
|
|
): OrderSummary {
|
|
|
|
|
const itemsSummary = itemRecords.map(record =>
|
2025-10-08 11:11:05 +09:00
|
|
|
transformSalesforceOrderItem(record).summary
|
2025-10-08 10:33:33 +09:00
|
|
|
);
|
2025-10-08 11:11:05 +09:00
|
|
|
return buildOrderSummary(order, itemsSummary);
|
2025-10-08 10:33:33 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function buildOrderSummary(
|
|
|
|
|
order: SalesforceOrderRecord,
|
2025-10-08 11:11:05 +09:00
|
|
|
itemsSummary: OrderItemSummary[]
|
2025-10-08 10:33:33 +09:00
|
|
|
): OrderSummary {
|
|
|
|
|
const effectiveDate =
|
|
|
|
|
ensureString(order.EffectiveDate) ??
|
|
|
|
|
ensureString(order.CreatedDate) ??
|
|
|
|
|
new Date().toISOString();
|
|
|
|
|
const createdDate = ensureString(order.CreatedDate) ?? effectiveDate;
|
|
|
|
|
const lastModifiedDate = ensureString(order.LastModifiedDate) ?? createdDate;
|
|
|
|
|
const totalAmount = coerceNumber(order.TotalAmount);
|
|
|
|
|
|
|
|
|
|
return orderSummarySchema.parse({
|
|
|
|
|
id: order.Id,
|
|
|
|
|
orderNumber: ensureString(order.OrderNumber) ?? order.Id,
|
|
|
|
|
status: ensureString(order.Status) ?? "Unknown",
|
2025-10-08 11:11:05 +09:00
|
|
|
orderType: order.Type ?? undefined,
|
2025-10-08 10:33:33 +09:00
|
|
|
effectiveDate,
|
|
|
|
|
totalAmount: typeof totalAmount === "number" ? totalAmount : undefined,
|
|
|
|
|
createdDate,
|
|
|
|
|
lastModifiedDate,
|
2025-10-08 11:11:05 +09:00
|
|
|
whmcsOrderId: order.WHMCS_Order_ID__c ?? undefined,
|
|
|
|
|
activationStatus: order.Activation_Status__c ?? undefined,
|
2025-10-08 10:33:33 +09:00
|
|
|
itemsSummary,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function ensureString(value: unknown): string | undefined {
|
|
|
|
|
return typeof value === "string" ? value : undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function coerceNumber(value: unknown): number | undefined {
|
|
|
|
|
if (typeof value === "number") return Number.isFinite(value) ? value : undefined;
|
|
|
|
|
if (typeof value === "string") {
|
|
|
|
|
const parsed = Number.parseFloat(value);
|
|
|
|
|
return Number.isFinite(parsed) ? parsed : undefined;
|
|
|
|
|
}
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function normalizeQuantity(value: unknown): number {
|
|
|
|
|
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
|
|
|
return Math.trunc(value);
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|