xpeditis2.0/apps/backend/src/application/dto/subscription.dto.ts
David 08787c89c8
Some checks failed
Dev CI / Unit Tests (${{ matrix.app }}) (backend) (push) Blocked by required conditions
Dev CI / Unit Tests (${{ matrix.app }}) (frontend) (push) Blocked by required conditions
Dev CI / Notify Failure (push) Blocked by required conditions
Dev CI / Quality (${{ matrix.app }}) (backend) (push) Has been cancelled
Dev CI / Quality (${{ matrix.app }}) (frontend) (push) Has been cancelled
chore: sync full codebase from cicd branch
Aligns dev with the complete application codebase (cicd branch).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 12:56:16 +02:00

401 lines
8.5 KiB
TypeScript

/**
* Subscription DTOs
*
* Data Transfer Objects for subscription management API
*/
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsString, IsEnum, IsUrl, IsOptional } from 'class-validator';
/**
* Subscription plan types
*/
export enum SubscriptionPlanDto {
BRONZE = 'BRONZE',
SILVER = 'SILVER',
GOLD = 'GOLD',
PLATINIUM = 'PLATINIUM',
}
/**
* 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.SILVER,
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.SILVER,
description: 'Plan identifier',
enum: SubscriptionPlanDto,
})
plan: SubscriptionPlanDto;
@ApiProperty({
example: 'Silver',
description: 'Plan display name',
})
name: string;
@ApiProperty({
example: 5,
description: 'Maximum number of licenses (-1 for unlimited)',
})
maxLicenses: number;
@ApiProperty({
example: 249,
description: 'Monthly price in EUR',
})
monthlyPriceEur: number;
@ApiProperty({
example: 2739,
description: 'Yearly price in EUR (11 months)',
})
yearlyPriceEur: number;
@ApiProperty({
example: -1,
description: 'Maximum shipments per year (-1 for unlimited)',
})
maxShipmentsPerYear: number;
@ApiProperty({
example: 3,
description: 'Commission rate percentage on shipments',
})
commissionRatePercent: number;
@ApiProperty({
example: 'email',
description: 'Support level: none, email, direct, dedicated_kam',
})
supportLevel: string;
@ApiProperty({
example: 'silver',
description: 'Status badge: none, silver, gold, platinium',
})
statusBadge: string;
@ApiProperty({
example: ['dashboard', 'wiki', 'user_management', 'csv_export'],
description: 'List of plan feature flags',
type: [String],
})
planFeatures: string[];
@ApiProperty({
example: ["Jusqu'à 5 utilisateurs", 'Expéditions illimitées', 'Import CSV'],
description: 'List of human-readable 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.SILVER,
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[];
}