2025-10-08 10:33:33 +09:00
|
|
|
/**
|
|
|
|
|
* Orders Domain - Validation
|
2025-12-12 14:35:19 +09:00
|
|
|
*
|
2025-10-08 10:33:33 +09:00
|
|
|
* Extended business validation rules for orders.
|
|
|
|
|
* These rules represent domain logic and should be reusable across frontend/backend.
|
|
|
|
|
*/
|
|
|
|
|
|
2025-12-12 14:35:19 +09:00
|
|
|
import type { infer as ZodInfer } from "zod";
|
2025-12-10 15:22:10 +09:00
|
|
|
import { orderBusinessValidationSchema } from "./schema.js";
|
2025-10-08 10:33:33 +09:00
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// 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(
|
2025-12-12 14:35:19 +09:00
|
|
|
sku =>
|
2025-10-08 10:33:33 +09:00
|
|
|
sku.toUpperCase().includes("SIM") &&
|
|
|
|
|
!sku.toUpperCase().includes("ACTIVATION") &&
|
|
|
|
|
!sku.toUpperCase().includes("ADDON")
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if SKUs array contains a SIM activation fee
|
|
|
|
|
*/
|
2025-11-18 10:57:36 +09:00
|
|
|
export function hasSimActivationFee(_skus: string[]): boolean {
|
|
|
|
|
// Deprecated: rely on catalog metadata instead of heuristics.
|
|
|
|
|
return true;
|
2025-10-08 10:33:33 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if SKUs array contains a VPN activation fee
|
|
|
|
|
*/
|
|
|
|
|
export function hasVpnActivationFee(skus: string[]): boolean {
|
|
|
|
|
return skus.some(
|
2025-12-12 14:35:19 +09:00
|
|
|
sku => sku.toUpperCase().includes("VPN") && sku.toUpperCase().includes("ACTIVATION")
|
2025-10-08 10:33:33 +09:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if SKUs array contains an Internet service plan
|
|
|
|
|
* (excludes installation and addons)
|
|
|
|
|
*/
|
|
|
|
|
export function hasInternetServicePlan(skus: string[]): boolean {
|
|
|
|
|
return skus.some(
|
2025-12-12 14:35:19 +09:00
|
|
|
sku =>
|
2025-10-08 10:33:33 +09:00
|
|
|
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[] {
|
2025-12-12 14:35:19 +09:00
|
|
|
return skus.filter(sku => {
|
2025-10-08 10:33:33 +09:00
|
|
|
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
|
2025-12-12 14:35:19 +09:00
|
|
|
*
|
2025-10-08 16:31:42 +09:00
|
|
|
* This schema delegates to the helper functions above for DRY validation.
|
|
|
|
|
* Helper functions are reusable in both schema refinements and imperative validation.
|
2025-12-12 14:35:19 +09:00
|
|
|
*
|
2025-10-08 10:33:33 +09:00
|
|
|
* 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
|
2025-12-12 14:35:19 +09:00
|
|
|
.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"],
|
|
|
|
|
});
|
2025-10-08 10:33:33 +09:00
|
|
|
|
2025-12-12 14:35:19 +09:00
|
|
|
export type OrderWithSkuValidation = ZodInfer<typeof orderWithSkuValidationSchema>;
|
2025-10-08 10:33:33 +09:00
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// 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;
|
|
|
|
|
}
|