import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { IsArray, IsBoolean, IsEnum, IsInt, IsOptional, IsString, Max, Min, ValidateNested, } from 'class-validator'; import { Type } from 'class-transformer'; import { BillingCycle } from '../../common/enums'; import { CalculateCostDto, UpgradeResourcesDto } from './billing.dto'; export class CreateDiscountDto { @ApiProperty({ example: 'NOWRUZ1403' }) @IsString() code: string; @ApiProperty({ example: 'تخفیف نوروزی' }) @IsString() name: string; @ApiPropertyOptional() @IsOptional() @IsString() description?: string; @ApiProperty({ example: 20, description: 'Percentage off (1–100)' }) @IsInt() @Min(1) @Max(100) percentOff: number; @ApiPropertyOptional({ type: [String], description: 'Service keys to target. Empty or ["*"] = all services.', example: ['optional:redis', 'runtime:nodejs'], }) @IsOptional() @IsArray() @IsString({ each: true }) services?: string[]; @ApiPropertyOptional({ default: true }) @IsOptional() @IsBoolean() isPublic?: boolean; @ApiPropertyOptional({ type: [String] }) @IsOptional() @IsArray() @IsString({ each: true }) allowedUserIds?: string[]; @ApiPropertyOptional({ description: 'Total redemption cap (omit for unlimited)' }) @IsOptional() @IsInt() @Min(1) maxUses?: number; @ApiPropertyOptional({ description: 'Per-user redemption cap (omit for unlimited)' }) @IsOptional() @IsInt() @Min(1) maxUsesPerUser?: number; @ApiPropertyOptional({ description: 'ISO start date' }) @IsOptional() @IsString() startsAt?: string; @ApiPropertyOptional({ description: 'ISO end date' }) @IsOptional() @IsString() endsAt?: string; @ApiPropertyOptional({ default: true }) @IsOptional() @IsBoolean() isActive?: boolean; } export class UpdateDiscountDto { @ApiPropertyOptional() @IsOptional() @IsString() code?: string; @ApiPropertyOptional() @IsOptional() @IsString() name?: string; @ApiPropertyOptional() @IsOptional() @IsString() description?: string; @ApiPropertyOptional({ example: 20 }) @IsOptional() @IsInt() @Min(1) @Max(100) percentOff?: number; @ApiPropertyOptional({ type: [String] }) @IsOptional() @IsArray() @IsString({ each: true }) services?: string[]; @ApiPropertyOptional() @IsOptional() @IsBoolean() isPublic?: boolean; @ApiPropertyOptional({ type: [String] }) @IsOptional() @IsArray() @IsString({ each: true }) allowedUserIds?: string[]; @ApiPropertyOptional() @IsOptional() @IsInt() @Min(1) maxUses?: number | null; @ApiPropertyOptional() @IsOptional() @IsInt() @Min(1) maxUsesPerUser?: number | null; @ApiPropertyOptional() @IsOptional() @IsString() startsAt?: string | null; @ApiPropertyOptional() @IsOptional() @IsString() endsAt?: string | null; @ApiPropertyOptional() @IsOptional() @IsBoolean() isActive?: boolean; } export enum DiscountFlow { DEPLOY = 'deploy', RENEWAL = 'renewal', UPGRADE = 'upgrade', } /** Validate a coupon against a concrete charge context to preview the discount. */ export class ValidateDiscountDto { @ApiProperty({ example: 'NOWRUZ1403' }) @IsString() code: string; @ApiProperty({ enum: BillingCycle }) @IsEnum(BillingCycle) cycle: BillingCycle; @ApiPropertyOptional({ enum: DiscountFlow, default: DiscountFlow.DEPLOY }) @IsOptional() @IsEnum(DiscountFlow) flow?: DiscountFlow; @ApiPropertyOptional({ type: CalculateCostDto, description: 'Deploy config (deploy flow)' }) @IsOptional() @ValidateNested() @Type(() => CalculateCostDto) config?: CalculateCostDto; @ApiPropertyOptional({ description: 'Application id (renewal/upgrade flows)' }) @IsOptional() @IsString() applicationId?: string; @ApiPropertyOptional({ type: UpgradeResourcesDto, description: 'Target resources (upgrade flow)' }) @IsOptional() @ValidateNested() @Type(() => UpgradeResourcesDto) upgrade?: UpgradeResourcesDto; }