379 lines
7.8 KiB
TypeScript
379 lines
7.8 KiB
TypeScript
/**
|
|
* Subscription DTOs
|
|
*
|
|
* Data Transfer Objects for subscription management API
|
|
*/
|
|
|
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
|
import {
|
|
IsString,
|
|
IsEnum,
|
|
IsNotEmpty,
|
|
IsUrl,
|
|
IsOptional,
|
|
IsBoolean,
|
|
IsInt,
|
|
Min,
|
|
} from 'class-validator';
|
|
|
|
/**
|
|
* Subscription plan types
|
|
*/
|
|
export enum SubscriptionPlanDto {
|
|
FREE = 'FREE',
|
|
STARTER = 'STARTER',
|
|
PRO = 'PRO',
|
|
ENTERPRISE = 'ENTERPRISE',
|
|
}
|
|
|
|
/**
|
|
* Subscription status types
|
|
*/
|
|
export enum SubscriptionStatusDto {
|
|
ACTIVE = 'ACTIVE',
|
|
PAST_DUE = 'PAST_DUE',
|
|
CANCELED = 'CANCELED',
|
|
INCOMPLETE = 'INCOMPLETE',
|
|
INCOMPLETE_EXPIRED = 'INCOMPLETE_EXPIRED',
|
|
TRIALING = 'TRIALING',
|
|
UNPAID = 'UNPAID',
|
|
PAUSED = 'PAUSED',
|
|
}
|
|
|
|
/**
|
|
* Billing interval types
|
|
*/
|
|
export enum BillingIntervalDto {
|
|
MONTHLY = 'monthly',
|
|
YEARLY = 'yearly',
|
|
}
|
|
|
|
/**
|
|
* Create Checkout Session DTO
|
|
*/
|
|
export class CreateCheckoutSessionDto {
|
|
@ApiProperty({
|
|
example: SubscriptionPlanDto.STARTER,
|
|
description: 'The subscription plan to purchase',
|
|
enum: SubscriptionPlanDto,
|
|
})
|
|
@IsEnum(SubscriptionPlanDto)
|
|
plan: SubscriptionPlanDto;
|
|
|
|
@ApiProperty({
|
|
example: BillingIntervalDto.MONTHLY,
|
|
description: 'Billing interval (monthly or yearly)',
|
|
enum: BillingIntervalDto,
|
|
})
|
|
@IsEnum(BillingIntervalDto)
|
|
billingInterval: BillingIntervalDto;
|
|
|
|
@ApiPropertyOptional({
|
|
example: 'https://app.xpeditis.com/dashboard/settings/subscription?success=true',
|
|
description: 'URL to redirect to after successful payment',
|
|
})
|
|
@IsUrl()
|
|
@IsOptional()
|
|
successUrl?: string;
|
|
|
|
@ApiPropertyOptional({
|
|
example: 'https://app.xpeditis.com/dashboard/settings/subscription?canceled=true',
|
|
description: 'URL to redirect to if payment is canceled',
|
|
})
|
|
@IsUrl()
|
|
@IsOptional()
|
|
cancelUrl?: string;
|
|
}
|
|
|
|
/**
|
|
* Create Portal Session DTO
|
|
*/
|
|
export class CreatePortalSessionDto {
|
|
@ApiPropertyOptional({
|
|
example: 'https://app.xpeditis.com/dashboard/settings/subscription',
|
|
description: 'URL to return to after using the portal',
|
|
})
|
|
@IsUrl()
|
|
@IsOptional()
|
|
returnUrl?: string;
|
|
}
|
|
|
|
/**
|
|
* Sync Subscription DTO
|
|
*/
|
|
export class SyncSubscriptionDto {
|
|
@ApiPropertyOptional({
|
|
example: 'cs_test_a1b2c3d4e5f6g7h8',
|
|
description: 'Stripe checkout session ID (used after checkout completes)',
|
|
})
|
|
@IsString()
|
|
@IsOptional()
|
|
sessionId?: string;
|
|
}
|
|
|
|
/**
|
|
* Checkout Session Response DTO
|
|
*/
|
|
export class CheckoutSessionResponseDto {
|
|
@ApiProperty({
|
|
example: 'cs_test_a1b2c3d4e5f6g7h8',
|
|
description: 'Stripe checkout session ID',
|
|
})
|
|
sessionId: string;
|
|
|
|
@ApiProperty({
|
|
example: 'https://checkout.stripe.com/pay/cs_test_a1b2c3',
|
|
description: 'URL to redirect user to for payment',
|
|
})
|
|
sessionUrl: string;
|
|
}
|
|
|
|
/**
|
|
* Portal Session Response DTO
|
|
*/
|
|
export class PortalSessionResponseDto {
|
|
@ApiProperty({
|
|
example: 'https://billing.stripe.com/session/test_YWNjdF8x',
|
|
description: 'URL to redirect user to for subscription management',
|
|
})
|
|
sessionUrl: string;
|
|
}
|
|
|
|
/**
|
|
* License Response DTO
|
|
*/
|
|
export class LicenseResponseDto {
|
|
@ApiProperty({
|
|
example: '550e8400-e29b-41d4-a716-446655440000',
|
|
description: 'License ID',
|
|
})
|
|
id: string;
|
|
|
|
@ApiProperty({
|
|
example: '550e8400-e29b-41d4-a716-446655440001',
|
|
description: 'User ID',
|
|
})
|
|
userId: string;
|
|
|
|
@ApiProperty({
|
|
example: 'john.doe@example.com',
|
|
description: 'User email',
|
|
})
|
|
userEmail: string;
|
|
|
|
@ApiProperty({
|
|
example: 'John Doe',
|
|
description: 'User full name',
|
|
})
|
|
userName: string;
|
|
|
|
@ApiProperty({
|
|
example: 'ADMIN',
|
|
description: 'User role (ADMIN users have unlimited licenses)',
|
|
})
|
|
userRole: string;
|
|
|
|
@ApiProperty({
|
|
example: 'ACTIVE',
|
|
description: 'License status',
|
|
})
|
|
status: string;
|
|
|
|
@ApiProperty({
|
|
example: '2025-01-15T10:00:00Z',
|
|
description: 'When the license was assigned',
|
|
})
|
|
assignedAt: Date;
|
|
|
|
@ApiPropertyOptional({
|
|
example: '2025-02-15T10:00:00Z',
|
|
description: 'When the license was revoked (if applicable)',
|
|
})
|
|
revokedAt?: Date;
|
|
}
|
|
|
|
/**
|
|
* Plan Details DTO
|
|
*/
|
|
export class PlanDetailsDto {
|
|
@ApiProperty({
|
|
example: SubscriptionPlanDto.STARTER,
|
|
description: 'Plan identifier',
|
|
enum: SubscriptionPlanDto,
|
|
})
|
|
plan: SubscriptionPlanDto;
|
|
|
|
@ApiProperty({
|
|
example: 'Starter',
|
|
description: 'Plan display name',
|
|
})
|
|
name: string;
|
|
|
|
@ApiProperty({
|
|
example: 5,
|
|
description: 'Maximum number of licenses (-1 for unlimited)',
|
|
})
|
|
maxLicenses: number;
|
|
|
|
@ApiProperty({
|
|
example: 49,
|
|
description: 'Monthly price in EUR',
|
|
})
|
|
monthlyPriceEur: number;
|
|
|
|
@ApiProperty({
|
|
example: 470,
|
|
description: 'Yearly price in EUR',
|
|
})
|
|
yearlyPriceEur: number;
|
|
|
|
@ApiProperty({
|
|
example: ['Up to 5 users', 'Advanced rate search', 'CSV imports'],
|
|
description: 'List of features included in this plan',
|
|
type: [String],
|
|
})
|
|
features: string[];
|
|
}
|
|
|
|
/**
|
|
* Subscription Response DTO
|
|
*/
|
|
export class SubscriptionResponseDto {
|
|
@ApiProperty({
|
|
example: '550e8400-e29b-41d4-a716-446655440000',
|
|
description: 'Subscription ID',
|
|
})
|
|
id: string;
|
|
|
|
@ApiProperty({
|
|
example: '550e8400-e29b-41d4-a716-446655440001',
|
|
description: 'Organization ID',
|
|
})
|
|
organizationId: string;
|
|
|
|
@ApiProperty({
|
|
example: SubscriptionPlanDto.STARTER,
|
|
description: 'Current subscription plan',
|
|
enum: SubscriptionPlanDto,
|
|
})
|
|
plan: SubscriptionPlanDto;
|
|
|
|
@ApiProperty({
|
|
description: 'Details about the current plan',
|
|
type: PlanDetailsDto,
|
|
})
|
|
planDetails: PlanDetailsDto;
|
|
|
|
@ApiProperty({
|
|
example: SubscriptionStatusDto.ACTIVE,
|
|
description: 'Current subscription status',
|
|
enum: SubscriptionStatusDto,
|
|
})
|
|
status: SubscriptionStatusDto;
|
|
|
|
@ApiProperty({
|
|
example: 3,
|
|
description: 'Number of licenses currently in use',
|
|
})
|
|
usedLicenses: number;
|
|
|
|
@ApiProperty({
|
|
example: 5,
|
|
description: 'Maximum licenses available (-1 for unlimited)',
|
|
})
|
|
maxLicenses: number;
|
|
|
|
@ApiProperty({
|
|
example: 2,
|
|
description: 'Number of licenses available',
|
|
})
|
|
availableLicenses: number;
|
|
|
|
@ApiProperty({
|
|
example: false,
|
|
description: 'Whether the subscription is scheduled for cancellation',
|
|
})
|
|
cancelAtPeriodEnd: boolean;
|
|
|
|
@ApiPropertyOptional({
|
|
example: '2025-01-01T00:00:00Z',
|
|
description: 'Start of current billing period',
|
|
})
|
|
currentPeriodStart?: Date;
|
|
|
|
@ApiPropertyOptional({
|
|
example: '2025-02-01T00:00:00Z',
|
|
description: 'End of current billing period',
|
|
})
|
|
currentPeriodEnd?: Date;
|
|
|
|
@ApiProperty({
|
|
example: '2025-01-01T00:00:00Z',
|
|
description: 'When the subscription was created',
|
|
})
|
|
createdAt: Date;
|
|
|
|
@ApiProperty({
|
|
example: '2025-01-15T10:00:00Z',
|
|
description: 'When the subscription was last updated',
|
|
})
|
|
updatedAt: Date;
|
|
}
|
|
|
|
/**
|
|
* Subscription Overview Response DTO (includes licenses)
|
|
*/
|
|
export class SubscriptionOverviewResponseDto extends SubscriptionResponseDto {
|
|
@ApiProperty({
|
|
description: 'List of active licenses',
|
|
type: [LicenseResponseDto],
|
|
})
|
|
licenses: LicenseResponseDto[];
|
|
}
|
|
|
|
/**
|
|
* Can Invite Response DTO
|
|
*/
|
|
export class CanInviteResponseDto {
|
|
@ApiProperty({
|
|
example: true,
|
|
description: 'Whether the organization can invite more users',
|
|
})
|
|
canInvite: boolean;
|
|
|
|
@ApiProperty({
|
|
example: 2,
|
|
description: 'Number of available licenses',
|
|
})
|
|
availableLicenses: number;
|
|
|
|
@ApiProperty({
|
|
example: 3,
|
|
description: 'Number of used licenses',
|
|
})
|
|
usedLicenses: number;
|
|
|
|
@ApiProperty({
|
|
example: 5,
|
|
description: 'Maximum licenses allowed (-1 for unlimited)',
|
|
})
|
|
maxLicenses: number;
|
|
|
|
@ApiPropertyOptional({
|
|
example: 'Upgrade to Starter plan to add more users',
|
|
description: 'Message explaining why invitations are blocked',
|
|
})
|
|
message?: string;
|
|
}
|
|
|
|
/**
|
|
* All Plans Response DTO
|
|
*/
|
|
export class AllPlansResponseDto {
|
|
@ApiProperty({
|
|
description: 'List of all available plans',
|
|
type: [PlanDetailsDto],
|
|
})
|
|
plans: PlanDetailsDto[];
|
|
}
|