/** * Subscriptions Domain - Schemas * * Zod validation schemas for subscription domain types. */ import { z } from "zod"; import { apiSuccessMessageResponseSchema } from "../common/schema.js"; // Subscription Status Schema export const subscriptionStatusSchema = z.enum([ "Active", "Inactive", "Pending", "Cancelled", "Suspended", "Terminated", "Completed", ]); // Subscription Cycle Schema export const subscriptionCycleSchema = z.enum([ "Monthly", "Quarterly", "Semi-Annually", "Annually", "Biennially", "Triennially", "One-time", "Free", ]); // Subscription Schema export const subscriptionSchema = z.object({ id: z.number().int().positive("Subscription id must be positive"), serviceId: z.number().int().positive("Service id must be positive"), productName: z.string().min(1, "Product name is required"), domain: z.string().optional(), cycle: subscriptionCycleSchema, status: subscriptionStatusSchema, nextDue: z.string().optional(), amount: z.number(), currency: z.string().min(1, "Currency is required"), currencySymbol: z.string().optional(), registrationDate: z.string().min(1, "Registration date is required"), notes: z.string().optional(), customFields: z.record(z.string(), z.string()).optional(), orderNumber: z.string().optional(), groupName: z.string().optional(), paymentMethod: z.string().optional(), serverName: z.string().optional(), }); export const subscriptionArraySchema = z.array(subscriptionSchema); // Subscription List Schema export const subscriptionListSchema = z.object({ subscriptions: z.array(subscriptionSchema), totalCount: z.number().int().nonnegative(), }); // ============================================================================ // Route Param Schemas (BFF) // ============================================================================ export const subscriptionIdParamSchema = z.object({ id: z.coerce.number().int().positive("Subscription id must be positive"), }); export type SubscriptionIdParam = z.infer; // ============================================================================ // Query Parameter Schemas // ============================================================================ /** * Schema for subscription query parameters */ export const subscriptionQueryParamsSchema = z.object({ page: z.coerce.number().int().positive().optional(), limit: z.coerce.number().int().positive().max(100).optional(), status: subscriptionStatusSchema.optional(), type: z.string().optional(), }); export type SubscriptionQueryParams = z.infer; export const subscriptionQuerySchema = subscriptionQueryParamsSchema; export type SubscriptionQuery = SubscriptionQueryParams; // ============================================================================ // Response Schemas // ============================================================================ /** * Schema for subscription statistics */ export const subscriptionStatsSchema = z.object({ total: z.number().int().nonnegative(), active: z.number().int().nonnegative(), completed: z.number().int().nonnegative(), cancelled: z.number().int().nonnegative(), }); /** * Schema for SIM action responses (top-up, cancellation, feature updates) */ export const simActionResponseSchema = apiSuccessMessageResponseSchema.extend({ data: z.unknown().optional(), }); /** * Schema for SIM plan change result with IP addresses */ export const simPlanChangeResultSchema = apiSuccessMessageResponseSchema.extend({ ipv4: z.string().optional(), ipv6: z.string().optional(), scheduledAt: z .string() .regex(/^\d{8}$/, "Scheduled date must be in YYYYMMDD format") .optional(), }); // ============================================================================ // Inferred Types from Schemas (Schema-First Approach) // ============================================================================ export type SubscriptionStatus = z.infer; export type SubscriptionCycle = z.infer; export type Subscription = z.infer; export type SubscriptionArray = z.infer; export type SubscriptionList = z.infer; export type SubscriptionStats = z.infer; export type SimActionResponse = z.infer; export type SimPlanChangeResult = z.infer; // ============================================================================ // Internet Cancellation Schemas // ============================================================================ /** * Available cancellation month for the customer */ export const internetCancellationMonthSchema = z.object({ value: z.string(), // YYYY-MM format label: z.string(), // Display label like "November 2025" }); /** * Internet cancellation preview response (service details + available months) */ export const internetCancellationPreviewSchema = z.object({ productName: z.string(), billingAmount: z.number(), nextDueDate: z.string().optional(), registrationDate: z.string().optional(), availableMonths: z.array(internetCancellationMonthSchema), customerEmail: z.string(), customerName: z.string(), }); /** * Internet cancellation request from customer */ export const internetCancelRequestSchema = z.object({ cancellationMonth: z .string() .regex(/^\d{4}-\d{2}$/, "Cancellation month must be in YYYY-MM format"), confirmRead: z.boolean(), confirmCancel: z.boolean(), alternativeEmail: z.string().email().optional().or(z.literal("")), comments: z.string().max(1000).optional(), }); export type InternetCancellationMonth = z.infer; export type InternetCancellationPreview = z.infer; export type InternetCancelRequest = z.infer;