xpeditis2.0/apps/backend/src/application/dto/subscription.dto.ts
2026-01-20 11:28:54 +01:00

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[];
}