/** * Orders Domain - Salesforce Provider Mapper * * Transforms Salesforce Order and OrderItem records into domain contracts. */ import type { OrderDetails, OrderItemDetails, OrderItemSummary, OrderSummary, } from "../../contract.js"; import { normalizeBillingCycle } from "../../helpers.js"; import { orderDetailsSchema, orderSummarySchema, orderItemDetailsSchema } from "../../schema.js"; import type { SalesforceProduct2WithPricebookEntries, SalesforcePricebookEntryRecord, } from "#internal/services/providers/salesforce"; import { defaultSalesforceOrderFieldMap, type SalesforceOrderFieldMap } from "./field-map.js"; import type { SalesforceOrderItemRecord, SalesforceOrderRecord } from "./raw.types.js"; /** * Helper function to get sort priority for item class */ function getItemClassSortPriority(itemClass?: string): number { if (!itemClass) return 4; const normalized = itemClass.toLowerCase(); if (normalized === "service") return 1; if (normalized === "installation" || normalized === "activation") return 2; if (normalized === "add-on") return 3; return 4; } /** * Transform a Salesforce OrderItem record into domain details + summary. */ export function transformSalesforceOrderItem( record: SalesforceOrderItemRecord, fieldMap: SalesforceOrderFieldMap = defaultSalesforceOrderFieldMap ): { details: OrderItemDetails; summary: OrderItemSummary } { const pricebookEntry = (record.PricebookEntry ?? null) as SalesforcePricebookEntryRecord | null; const product = pricebookEntry?.Product2 as SalesforceProduct2WithPricebookEntries | undefined; const orderItemFields = fieldMap.orderItem; const productFields = fieldMap.product; const billingCycleRaw = record[orderItemFields.billingCycle] ?? (product ? (product[productFields.billingCycle] as unknown) : undefined); const billingCycle = billingCycleRaw !== undefined && billingCycleRaw !== null ? normalizeBillingCycle(billingCycleRaw) : undefined; const details = orderItemDetailsSchema.parse({ id: record.Id, orderId: ensureString(record.OrderId) ?? "", quantity: normalizeQuantity(record.Quantity), unitPrice: coerceNumber(record.UnitPrice), totalPrice: coerceNumber(record.TotalPrice), billingCycle, product: product ? { id: ensureString(product.Id), name: ensureString(product.Name), sku: ensureString(product[productFields.sku]) ?? undefined, itemClass: ensureString(product[productFields.itemClass]) ?? undefined, whmcsProductId: resolveWhmcsProductId(product[productFields.whmcsProductId]), internetOfferingType: ensureString(product[productFields.internetOfferingType]) ?? undefined, internetPlanTier: ensureString(product[productFields.internetPlanTier]) ?? undefined, vpnRegion: ensureString(product[productFields.vpnRegion]) ?? undefined, isBundledAddon: coerceBoolean(product[productFields.isBundledAddon]), bundledAddonId: ensureString(product[productFields.bundledAddon]) ?? undefined, } : undefined, }); return { details, summary: { productName: details.product?.name, name: details.product?.name, sku: details.product?.sku, productId: details.product?.id, status: undefined, billingCycle: details.billingCycle, itemClass: details.product?.itemClass, quantity: details.quantity, unitPrice: details.unitPrice, totalPrice: details.totalPrice, isBundledAddon: details.product?.isBundledAddon, bundledAddonId: details.product?.bundledAddonId, }, }; } /** * Transform a Salesforce Order record (with associated OrderItems) into domain OrderDetails. */ export function transformSalesforceOrderDetails( order: SalesforceOrderRecord, itemRecords: SalesforceOrderItemRecord[], fieldMap: SalesforceOrderFieldMap = defaultSalesforceOrderFieldMap ): OrderDetails { const transformedItems = itemRecords.map(record => transformSalesforceOrderItem(record, fieldMap) ); // Sort items by item class priority (Service -> Installation/Activation -> Add-on -> Others) transformedItems.sort((a, b) => { const priorityA = getItemClassSortPriority(a.summary.itemClass); const priorityB = getItemClassSortPriority(b.summary.itemClass); return priorityA - priorityB; }); const items = transformedItems.map(item => item.details); const itemsSummary = transformedItems.map(item => item.summary); const summary = buildOrderSummary(order, itemsSummary, fieldMap); const orderFields = fieldMap.order; return orderDetailsSchema.parse({ ...summary, accountId: ensureString(order.AccountId), accountName: ensureString(order.Account?.Name), pricebook2Id: ensureString(order.Pricebook2Id), opportunityId: ensureString(order.OpportunityId), // Linked Opportunity for lifecycle tracking activationType: ensureString(order[orderFields.activationType]), activationStatus: summary.activationStatus, activationScheduledAt: ensureString(order[orderFields.activationScheduledAt]), activationErrorCode: ensureString(order[orderFields.activationErrorCode]), activationErrorMessage: ensureString(order[orderFields.activationErrorMessage]), activatedDate: ensureString(order.ActivatedDate), items, }); } /** * Transform a Salesforce Order record (with optional OrderItems) into domain OrderSummary. */ export function transformSalesforceOrderSummary( order: SalesforceOrderRecord, itemRecords: SalesforceOrderItemRecord[], fieldMap: SalesforceOrderFieldMap = defaultSalesforceOrderFieldMap ): OrderSummary { const transformedItems = itemRecords.map(record => transformSalesforceOrderItem(record, fieldMap) ); // Sort items by item class priority (Service -> Installation/Activation -> Add-on -> Others) transformedItems.sort((a, b) => { const priorityA = getItemClassSortPriority(a.summary.itemClass); const priorityB = getItemClassSortPriority(b.summary.itemClass); return priorityA - priorityB; }); const itemsSummary = transformedItems.map(item => item.summary); return buildOrderSummary(order, itemsSummary, fieldMap); } function buildOrderSummary( order: SalesforceOrderRecord, itemsSummary: OrderItemSummary[], fieldMap: SalesforceOrderFieldMap ): OrderSummary { const orderFields = fieldMap.order; 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", orderType: ensureString(order[orderFields.type]) ?? undefined, effectiveDate, totalAmount: typeof totalAmount === "number" ? totalAmount : undefined, createdDate, lastModifiedDate, whmcsOrderId: ensureString(order[orderFields.whmcsOrderId]) ?? undefined, activationStatus: ensureString(order[orderFields.activationStatus]) ?? undefined, 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; } function resolveWhmcsProductId(value: unknown): string | undefined { if (value === null || value === undefined) { return undefined; } if (typeof value === "number") { return Number.isFinite(value) ? String(value) : undefined; } if (typeof value === "string") { return value; } return undefined; } function coerceBoolean(value: unknown): boolean | undefined { if (typeof value === "boolean") { return value; } return undefined; }