/** * Orders Domain - Validation * * Extended business validation rules for orders. * These rules represent domain logic and should be reusable across frontend/backend. */ import { z } from "zod"; import { orderBusinessValidationSchema } from "./schema.js"; // ============================================================================ // SKU Business Rules Helpers // ============================================================================ /** * Check if SKUs array contains a SIM service plan * (excludes activation fees and addons) */ export function hasSimServicePlan(skus: string[]): boolean { return skus.some( (sku) => sku.toUpperCase().includes("SIM") && !sku.toUpperCase().includes("ACTIVATION") && !sku.toUpperCase().includes("ADDON") ); } /** * Check if SKUs array contains a SIM activation fee */ export function hasSimActivationFee(_skus: string[]): boolean { // Deprecated: rely on catalog metadata instead of heuristics. return true; } /** * Check if SKUs array contains a VPN activation fee */ export function hasVpnActivationFee(skus: string[]): boolean { return skus.some( (sku) => sku.toUpperCase().includes("VPN") && sku.toUpperCase().includes("ACTIVATION") ); } /** * Check if SKUs array contains an Internet service plan * (excludes installation and addons) */ export function hasInternetServicePlan(skus: string[]): boolean { return skus.some( (sku) => sku.toUpperCase().includes("INTERNET") && !sku.toUpperCase().includes("INSTALL") && !sku.toUpperCase().includes("ADDON") ); } /** * Check if SKUs array contains main service SKUs for Internet orders * (filters out installation, addons, activation fees) */ export function getMainServiceSkus(skus: string[]): string[] { return skus.filter((sku) => { const upperSku = sku.toUpperCase(); return ( !upperSku.includes("INSTALL") && !upperSku.includes("ADDON") && !upperSku.includes("ACTIVATION") && !upperSku.includes("FEE") ); }); } // ============================================================================ // Extended Order Validation with SKU Business Rules // ============================================================================ /** * Complete order validation including all SKU business rules * * This schema delegates to the helper functions above for DRY validation. * Helper functions are reusable in both schema refinements and imperative validation. * * Validates: * - Basic order structure (from orderBusinessValidationSchema) * - SIM orders have service plan + activation fee * - VPN orders have activation fee * - Internet orders have service plan */ export const orderWithSkuValidationSchema = orderBusinessValidationSchema .refine( (data) => data.orderType !== "SIM" || hasSimServicePlan(data.skus), { message: "SIM orders must include a SIM service plan", path: ["skus"], } ) .refine( (data) => data.orderType !== "VPN" || hasVpnActivationFee(data.skus), { message: "VPN orders require an activation fee", path: ["skus"], } ) .refine( (data) => data.orderType !== "Internet" || hasInternetServicePlan(data.skus), { message: "Internet orders require a service plan", path: ["skus"], } ); export type OrderWithSkuValidation = z.infer; // ============================================================================ // Validation Error Messages // ============================================================================ /** * Get specific validation error message for order type */ export function getOrderTypeValidationError(orderType: string, skus: string[]): string | null { switch (orderType) { case "SIM": if (!hasSimServicePlan(skus)) { return "A SIM plan must be selected"; } break; case "VPN": if (!hasVpnActivationFee(skus)) { return "VPN orders require an activation fee"; } break; case "Internet": if (!hasInternetServicePlan(skus)) { return "Internet orders require a service plan"; } break; } return null; }