diff --git a/README.md b/README.md index ecf58c4a..2ee249db 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ NestJS PostgreSQL Apache 2.0 License - 2245 Tests Passing 12 AI Agents + 2249 Tests Passing 12 AI Agents

@@ -510,7 +510,7 @@ Operator notes for activating existing adapters, metasearch landings on the dire | OTA Channels | Booking.com + Expedia (EQC) + SiteMinder + DerbySoft | Direct + aggregated OTA connectivity (ARI + content) | | XML Processing | fast-xml-parser | Booking.com OTA XML protocol | | Package Manager | pnpm workspaces | Monorepo management | -| Testing | Vitest (2245 passing tests across 268 files with passing tests) | Unit and integration tests | +| Testing | Vitest (2249 passing tests across 269 files with passing tests) | Unit and integration tests | | Build | tsup (packages) + Vite (dashboard) + nest build (API) | Fast builds | | Containers | Docker + docker-compose | Local dev and production deployment | | CI/CD | GitHub Actions | Automated testing, builds, and releases | @@ -648,7 +648,7 @@ Before going live, verify the items in [`docs/deployment.md`](./docs/deployment. ### Run tests ```bash -# Passing-test count: 2245 test cases across 268 files (skipped excluded) +# Passing-test count: 2249 test cases across 269 files (skipped excluded) # API tests only pnpm --filter @telivityhaip/api test @@ -1197,7 +1197,7 @@ HAIP is built in public and contributions are welcome. pnpm install # Install dependencies pnpm build # Build all workspace packages pnpm dev # Start API in dev mode (hot reload) -pnpm test # Run all tests (2245 passing, 268 files with passes; skipped excluded) +pnpm test # Run all tests (2249 passing, 269 files with passes; skipped excluded) pnpm lint # ESLint ``` diff --git a/apps/api/src/modules/accounting/dto/create-accounting-code.dto.ts b/apps/api/src/modules/accounting/dto/create-accounting-code.dto.ts index d3a5e978..03eb5e29 100644 --- a/apps/api/src/modules/accounting/dto/create-accounting-code.dto.ts +++ b/apps/api/src/modules/accounting/dto/create-accounting-code.dto.ts @@ -3,7 +3,7 @@ import { IsNotEmpty, IsOptional, IsUUID, - IsEnum, + IsIn, MaxLength, } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; @@ -15,7 +15,7 @@ export class CreateAccountingCodeDto { propertyId!: string; @ApiProperty({ enum: ['transaction', 'gl'], description: 'Code kind (KB 5)' }) - @IsEnum(['transaction', 'gl']) + @IsIn(['transaction', 'gl']) kind!: string; @ApiProperty({ example: 'ROOM-REV', description: 'Code' }) diff --git a/apps/api/src/modules/accounting/dto/list-accounting-codes.dto.ts b/apps/api/src/modules/accounting/dto/list-accounting-codes.dto.ts index bdf1361b..f3713bdf 100644 --- a/apps/api/src/modules/accounting/dto/list-accounting-codes.dto.ts +++ b/apps/api/src/modules/accounting/dto/list-accounting-codes.dto.ts @@ -1,4 +1,4 @@ -import { IsOptional, IsUUID, IsEnum, IsBoolean, IsInt, Min, Max } from 'class-validator'; +import { IsOptional, IsUUID, IsIn, IsBoolean, IsInt, Min, Max } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; @@ -9,7 +9,7 @@ export class ListAccountingCodesDto { @ApiPropertyOptional({ enum: ['transaction', 'gl'] }) @IsOptional() - @IsEnum(['transaction', 'gl']) + @IsIn(['transaction', 'gl']) kind?: string; @ApiPropertyOptional({ description: 'Include archived codes', default: false }) diff --git a/apps/api/src/modules/accounting/dto/list-ar-ledgers.dto.ts b/apps/api/src/modules/accounting/dto/list-ar-ledgers.dto.ts index 4a7c0b79..a7b87723 100644 --- a/apps/api/src/modules/accounting/dto/list-ar-ledgers.dto.ts +++ b/apps/api/src/modules/accounting/dto/list-ar-ledgers.dto.ts @@ -1,4 +1,4 @@ -import { IsOptional, IsUUID, IsEnum, IsInt, Min, Max } from 'class-validator'; +import { IsOptional, IsUUID, IsIn, IsInt, Min, Max } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; @@ -9,7 +9,7 @@ export class ListArLedgersDto { @ApiPropertyOptional({ enum: ['open', 'closed'] }) @IsOptional() - @IsEnum(['open', 'closed']) + @IsIn(['open', 'closed']) status?: string; @ApiPropertyOptional({ default: 1 }) diff --git a/apps/api/src/modules/accounting/dto/list-deposits.dto.ts b/apps/api/src/modules/accounting/dto/list-deposits.dto.ts index d2169700..d8d64999 100644 --- a/apps/api/src/modules/accounting/dto/list-deposits.dto.ts +++ b/apps/api/src/modules/accounting/dto/list-deposits.dto.ts @@ -1,4 +1,4 @@ -import { IsOptional, IsUUID, IsEnum, IsInt, Min, Max } from 'class-validator'; +import { IsOptional, IsUUID, IsIn, IsInt, Min, Max } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; @@ -14,7 +14,7 @@ export class ListDepositsDto { @ApiPropertyOptional({ enum: ['held', 'applied', 'refunded', 'forfeited'] }) @IsOptional() - @IsEnum(['held', 'applied', 'refunded', 'forfeited']) + @IsIn(['held', 'applied', 'refunded', 'forfeited']) status?: string; @ApiPropertyOptional({ default: 1 }) diff --git a/apps/api/src/modules/admin/dto/create-user.dto.ts b/apps/api/src/modules/admin/dto/create-user.dto.ts index fe850581..5d6bece8 100644 --- a/apps/api/src/modules/admin/dto/create-user.dto.ts +++ b/apps/api/src/modules/admin/dto/create-user.dto.ts @@ -4,7 +4,7 @@ import { IsNotEmpty, IsOptional, IsEmail, - IsEnum, + IsIn, IsArray, MaxLength, } from 'class-validator'; @@ -30,7 +30,7 @@ export class CreateUserDto { @ApiPropertyOptional({ enum: USER_STATUSES, default: 'active' }) @IsOptional() - @IsEnum(USER_STATUSES) + @IsIn(USER_STATUSES) status?: (typeof USER_STATUSES)[number]; @ApiPropertyOptional({ format: 'uuid', description: 'Keycloak subject (link real login — LATER)' }) diff --git a/apps/api/src/modules/admin/dto/update-user.dto.ts b/apps/api/src/modules/admin/dto/update-user.dto.ts index 700af695..49486b6e 100644 --- a/apps/api/src/modules/admin/dto/update-user.dto.ts +++ b/apps/api/src/modules/admin/dto/update-user.dto.ts @@ -1,4 +1,4 @@ -import { IsString, IsOptional, IsEnum, MaxLength } from 'class-validator'; +import { IsString, IsOptional, IsIn, MaxLength } from 'class-validator'; import { ApiPropertyOptional } from '@nestjs/swagger'; import { USER_STATUSES } from './create-user.dto'; @@ -11,6 +11,6 @@ export class UpdateUserDto { @ApiPropertyOptional({ enum: USER_STATUSES }) @IsOptional() - @IsEnum(USER_STATUSES) + @IsIn(USER_STATUSES) status?: (typeof USER_STATUSES)[number]; } diff --git a/apps/api/src/modules/ancillary/dto/create-service.dto.ts b/apps/api/src/modules/ancillary/dto/create-service.dto.ts index f9651069..4afe6e03 100644 --- a/apps/api/src/modules/ancillary/dto/create-service.dto.ts +++ b/apps/api/src/modules/ancillary/dto/create-service.dto.ts @@ -4,7 +4,7 @@ import { IsOptional, IsUUID, IsBoolean, - IsEnum, + IsIn, IsArray, IsInt, Min, @@ -58,7 +58,7 @@ export class CreateServiceDto { description?: string; @ApiProperty({ enum: SERVICE_CHARGE_TYPES }) - @IsEnum(SERVICE_CHARGE_TYPES) + @IsIn(SERVICE_CHARGE_TYPES) chargeType!: (typeof SERVICE_CHARGE_TYPES)[number]; @ApiProperty({ example: '25.00' }) @@ -78,7 +78,7 @@ export class CreateServiceDto { taxCode?: string; @ApiProperty({ enum: SERVICE_POSTING_RULES }) - @IsEnum(SERVICE_POSTING_RULES) + @IsIn(SERVICE_POSTING_RULES) postingRule!: (typeof SERVICE_POSTING_RULES)[number]; @ApiPropertyOptional({ diff --git a/apps/api/src/modules/cashier/dto/record-movement.dto.ts b/apps/api/src/modules/cashier/dto/record-movement.dto.ts index 5d4bb1e5..8b964d30 100644 --- a/apps/api/src/modules/cashier/dto/record-movement.dto.ts +++ b/apps/api/src/modules/cashier/dto/record-movement.dto.ts @@ -3,7 +3,7 @@ import { IsNotEmpty, IsOptional, IsUUID, - IsEnum, + IsIn, } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; @@ -17,7 +17,7 @@ export class RecordMovementDto { propertyId!: string; @ApiProperty({ enum: ['payment', 'refund', 'paid_out', 'drop'], description: 'Movement type (KB 12.3)' }) - @IsEnum(['payment', 'refund', 'paid_out', 'drop']) + @IsIn(['payment', 'refund', 'paid_out', 'drop']) type!: string; @ApiProperty({ example: '50.00', description: 'Movement amount' }) diff --git a/apps/api/src/modules/channel/dto/create-channel-connection.dto.ts b/apps/api/src/modules/channel/dto/create-channel-connection.dto.ts index 2cb20da2..1979c3cd 100644 --- a/apps/api/src/modules/channel/dto/create-channel-connection.dto.ts +++ b/apps/api/src/modules/channel/dto/create-channel-connection.dto.ts @@ -1,4 +1,4 @@ -import { IsUUID, IsString, IsOptional, IsArray, ValidateNested, IsEnum } from 'class-validator'; +import { IsUUID, IsString, IsOptional, IsArray, ValidateNested, IsIn } from 'class-validator'; import { Type } from 'class-transformer'; export class RatePlanMappingDto { @@ -31,7 +31,7 @@ export class CreateChannelConnectionDto { adapterType!: string; @IsOptional() - @IsEnum(['push', 'pull', 'bidirectional']) + @IsIn(['push', 'pull', 'bidirectional']) syncDirection?: string; @IsOptional() diff --git a/apps/api/src/modules/channel/dto/inbound-reservation.dto.ts b/apps/api/src/modules/channel/dto/inbound-reservation.dto.ts index 4923228b..04137fe5 100644 --- a/apps/api/src/modules/channel/dto/inbound-reservation.dto.ts +++ b/apps/api/src/modules/channel/dto/inbound-reservation.dto.ts @@ -1,4 +1,4 @@ -import { IsUUID, IsString, IsOptional, IsNumber, IsDateString, IsEnum, ValidateNested } from 'class-validator'; +import { IsUUID, IsString, IsOptional, IsNumber, IsDateString, IsIn, ValidateNested } from 'class-validator'; import { Type } from 'class-transformer'; export class ChannelReservationDto { @@ -51,7 +51,7 @@ export class ChannelReservationDto { @IsString() specialRequests?: string; - @IsEnum(['new', 'modified', 'cancelled']) + @IsIn(['new', 'modified', 'cancelled']) status!: 'new' | 'modified' | 'cancelled'; } diff --git a/apps/api/src/modules/channel/dto/set-rate-override.dto.ts b/apps/api/src/modules/channel/dto/set-rate-override.dto.ts index dda88b2a..713b6d95 100644 --- a/apps/api/src/modules/channel/dto/set-rate-override.dto.ts +++ b/apps/api/src/modules/channel/dto/set-rate-override.dto.ts @@ -1,6 +1,6 @@ import { IsUUID, - IsEnum, + IsIn, IsNumber, IsOptional, IsDateString, @@ -24,7 +24,7 @@ export class SetRateOverrideDto { ratePlanId!: string; @ApiProperty({ enum: ['percentage', 'fixed'] }) - @IsEnum(['percentage', 'fixed']) + @IsIn(['percentage', 'fixed']) adjustmentType!: 'percentage' | 'fixed'; @ApiProperty({ diff --git a/apps/api/src/modules/channel/dto/update-channel-connection.dto.ts b/apps/api/src/modules/channel/dto/update-channel-connection.dto.ts index cedf6e34..d4024b30 100644 --- a/apps/api/src/modules/channel/dto/update-channel-connection.dto.ts +++ b/apps/api/src/modules/channel/dto/update-channel-connection.dto.ts @@ -1,4 +1,4 @@ -import { IsString, IsOptional, IsArray, ValidateNested, IsEnum } from 'class-validator'; +import { IsString, IsOptional, IsArray, ValidateNested, IsIn } from 'class-validator'; import { Type } from 'class-transformer'; import { RatePlanMappingDto, RoomTypeMappingDto } from './create-channel-connection.dto'; @@ -8,11 +8,11 @@ export class UpdateChannelConnectionDto { channelName?: string; @IsOptional() - @IsEnum(['active', 'inactive', 'pending_setup']) + @IsIn(['active', 'inactive', 'pending_setup']) status?: string; @IsOptional() - @IsEnum(['push', 'pull', 'bidirectional']) + @IsIn(['push', 'pull', 'bidirectional']) syncDirection?: string; @IsOptional() diff --git a/apps/api/src/modules/connect/dto/agent-book.dto.ts b/apps/api/src/modules/connect/dto/agent-book.dto.ts index 772278c2..5c015eda 100644 --- a/apps/api/src/modules/connect/dto/agent-book.dto.ts +++ b/apps/api/src/modules/connect/dto/agent-book.dto.ts @@ -5,7 +5,7 @@ import { IsNumber, IsOptional, IsEmail, - IsEnum, + IsIn, Min, } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; @@ -75,7 +75,7 @@ export class AgentBookDto { // Payment @ApiPropertyOptional({ enum: ['pay_at_property', 'prepaid', 'virtual_card'] }) @IsOptional() - @IsEnum(['pay_at_property', 'prepaid', 'virtual_card']) + @IsIn(['pay_at_property', 'prepaid', 'virtual_card']) paymentMethod?: 'pay_at_property' | 'prepaid' | 'virtual_card'; @ApiPropertyOptional() diff --git a/apps/api/src/modules/door-lock/dto/list-credentials.dto.ts b/apps/api/src/modules/door-lock/dto/list-credentials.dto.ts index 459648b4..5e94547f 100644 --- a/apps/api/src/modules/door-lock/dto/list-credentials.dto.ts +++ b/apps/api/src/modules/door-lock/dto/list-credentials.dto.ts @@ -1,4 +1,4 @@ -import { IsEnum, IsOptional, IsUUID, IsInt, Min, Max } from 'class-validator'; +import { IsIn, IsOptional, IsUUID, IsInt, Min, Max } from 'class-validator'; import { Type } from 'class-transformer'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; @@ -9,7 +9,7 @@ export class ListDoorLockCredentialsDto { @ApiPropertyOptional({ enum: ['active', 'revoked'] }) @IsOptional() - @IsEnum(['active', 'revoked']) + @IsIn(['active', 'revoked']) status?: 'active' | 'revoked'; @ApiPropertyOptional({ default: 1 }) diff --git a/apps/api/src/modules/folio-inbound/dto/post-folio-inbound-charge.dto.ts b/apps/api/src/modules/folio-inbound/dto/post-folio-inbound-charge.dto.ts index 48caa65c..3e9c2700 100644 --- a/apps/api/src/modules/folio-inbound/dto/post-folio-inbound-charge.dto.ts +++ b/apps/api/src/modules/folio-inbound/dto/post-folio-inbound-charge.dto.ts @@ -1,6 +1,6 @@ import { IsDateString, - IsEnum, + IsIn, IsNotEmpty, IsOptional, IsString, @@ -30,7 +30,7 @@ export class PostFolioInboundChargeDto { roomNumber!: string; @ApiProperty({ enum: INBOUND_CHARGE_TYPES, example: 'minibar' }) - @IsEnum(INBOUND_CHARGE_TYPES) + @IsIn(INBOUND_CHARGE_TYPES) type!: (typeof INBOUND_CHARGE_TYPES)[number]; @ApiProperty({ example: '18.50' }) diff --git a/apps/api/src/modules/folio/dto/create-charge.dto.ts b/apps/api/src/modules/folio/dto/create-charge.dto.ts index 6c17bb67..79ba6d1f 100644 --- a/apps/api/src/modules/folio/dto/create-charge.dto.ts +++ b/apps/api/src/modules/folio/dto/create-charge.dto.ts @@ -3,7 +3,7 @@ import { IsNotEmpty, IsOptional, IsUUID, - IsEnum, + IsIn, IsBoolean, IsDateString, MaxLength, @@ -20,7 +20,7 @@ export class CreateChargeDto { @ApiProperty({ enum: ['room', 'tax', 'food_beverage', 'minibar', 'phone', 'laundry', 'parking', 'spa', 'incidental', 'fee', 'adjustment', 'package'], }) - @IsEnum(['room', 'tax', 'food_beverage', 'minibar', 'phone', 'laundry', 'parking', 'spa', 'incidental', 'fee', 'adjustment', 'package']) + @IsIn(['room', 'tax', 'food_beverage', 'minibar', 'phone', 'laundry', 'parking', 'spa', 'incidental', 'fee', 'adjustment', 'package']) type!: string; @ApiProperty({ example: 'Room charge - Standard King' }) diff --git a/apps/api/src/modules/folio/dto/create-folio.dto.ts b/apps/api/src/modules/folio/dto/create-folio.dto.ts index 56c2e930..3a273b6b 100644 --- a/apps/api/src/modules/folio/dto/create-folio.dto.ts +++ b/apps/api/src/modules/folio/dto/create-folio.dto.ts @@ -3,7 +3,7 @@ import { IsNotEmpty, IsOptional, IsUUID, - IsEnum, + IsIn, MaxLength, } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; @@ -30,7 +30,7 @@ export class CreateFolioDto { guestId!: string; @ApiProperty({ enum: ['guest', 'master', 'city_ledger'], default: 'guest' }) - @IsEnum(['guest', 'master', 'city_ledger']) + @IsIn(['guest', 'master', 'city_ledger']) type!: string; @ApiProperty({ example: 'USD', description: 'ISO 4217 currency code' }) diff --git a/apps/api/src/modules/folio/dto/create-routing-rule.dto.ts b/apps/api/src/modules/folio/dto/create-routing-rule.dto.ts index 0b1b09ea..ce2bba33 100644 --- a/apps/api/src/modules/folio/dto/create-routing-rule.dto.ts +++ b/apps/api/src/modules/folio/dto/create-routing-rule.dto.ts @@ -2,7 +2,7 @@ import { IsNotEmpty, IsOptional, IsUUID, - IsEnum, + IsIn, IsInt, } from 'class-validator'; import { Type } from 'class-transformer'; @@ -38,7 +38,7 @@ export class CreateRoutingRuleDto { reservationId!: string; @ApiProperty({ enum: CHARGE_TYPES }) - @IsEnum(CHARGE_TYPES) + @IsIn(CHARGE_TYPES) chargeType!: string; @ApiProperty({ description: 'Folio that charges of this type post to' }) diff --git a/apps/api/src/modules/folio/dto/list-charges.dto.ts b/apps/api/src/modules/folio/dto/list-charges.dto.ts index 7d33ec00..639a5771 100644 --- a/apps/api/src/modules/folio/dto/list-charges.dto.ts +++ b/apps/api/src/modules/folio/dto/list-charges.dto.ts @@ -1,4 +1,4 @@ -import { IsOptional, IsUUID, IsEnum, IsDateString, IsInt, Min, Max } from 'class-validator'; +import { IsOptional, IsUUID, IsIn, IsDateString, IsInt, Min, Max } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; @@ -11,7 +11,7 @@ export class ListChargesDto { enum: ['room', 'tax', 'food_beverage', 'minibar', 'phone', 'laundry', 'parking', 'spa', 'incidental', 'fee', 'adjustment', 'package'], }) @IsOptional() - @IsEnum(['room', 'tax', 'food_beverage', 'minibar', 'phone', 'laundry', 'parking', 'spa', 'incidental', 'fee', 'adjustment', 'package']) + @IsIn(['room', 'tax', 'food_beverage', 'minibar', 'phone', 'laundry', 'parking', 'spa', 'incidental', 'fee', 'adjustment', 'package']) type?: string; @ApiPropertyOptional() diff --git a/apps/api/src/modules/folio/dto/list-folios.dto.ts b/apps/api/src/modules/folio/dto/list-folios.dto.ts index 1acf50e5..69a6e4dd 100644 --- a/apps/api/src/modules/folio/dto/list-folios.dto.ts +++ b/apps/api/src/modules/folio/dto/list-folios.dto.ts @@ -1,4 +1,4 @@ -import { IsOptional, IsUUID, IsEnum, IsInt, Min, Max } from 'class-validator'; +import { IsOptional, IsUUID, IsIn, IsInt, Min, Max } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; @@ -19,12 +19,12 @@ export class ListFoliosDto { @ApiPropertyOptional({ enum: ['guest', 'master', 'city_ledger'] }) @IsOptional() - @IsEnum(['guest', 'master', 'city_ledger']) + @IsIn(['guest', 'master', 'city_ledger']) type?: string; @ApiPropertyOptional({ enum: ['open', 'settled', 'closed'] }) @IsOptional() - @IsEnum(['open', 'settled', 'closed']) + @IsIn(['open', 'settled', 'closed']) status?: string; @ApiPropertyOptional({ default: 1 }) diff --git a/apps/api/src/modules/folio/dto/move-transactions.dto.ts b/apps/api/src/modules/folio/dto/move-transactions.dto.ts index 18d4dd8a..9e205106 100644 --- a/apps/api/src/modules/folio/dto/move-transactions.dto.ts +++ b/apps/api/src/modules/folio/dto/move-transactions.dto.ts @@ -2,7 +2,7 @@ import { IsNotEmpty, IsOptional, IsUUID, - IsEnum, + IsIn, } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; @@ -42,6 +42,6 @@ export class MoveTransactionsDto { @ApiPropertyOptional({ enum: CHARGE_TYPES, description: 'Move all charges of this type' }) @IsOptional() - @IsEnum(CHARGE_TYPES) + @IsIn(CHARGE_TYPES) chargeType?: string; } diff --git a/apps/api/src/modules/groups/dto/create-block.dto.ts b/apps/api/src/modules/groups/dto/create-block.dto.ts index 46500e5a..24678a98 100644 --- a/apps/api/src/modules/groups/dto/create-block.dto.ts +++ b/apps/api/src/modules/groups/dto/create-block.dto.ts @@ -2,7 +2,7 @@ import { IsUUID, IsString, IsOptional, - IsEnum, + IsIn, IsBoolean, IsInt, IsDateString, @@ -80,6 +80,6 @@ export class CreateBlockDto { @ApiPropertyOptional({ enum: BLOCK_STATUSES, default: 'tentative' }) @IsOptional() - @IsEnum(BLOCK_STATUSES) + @IsIn(BLOCK_STATUSES) status?: string; } diff --git a/apps/api/src/modules/groups/dto/create-group-profile.dto.ts b/apps/api/src/modules/groups/dto/create-group-profile.dto.ts index fac6bcc7..e6a7ab35 100644 --- a/apps/api/src/modules/groups/dto/create-group-profile.dto.ts +++ b/apps/api/src/modules/groups/dto/create-group-profile.dto.ts @@ -2,7 +2,7 @@ import { IsUUID, IsString, IsOptional, - IsEnum, + IsIn, IsBoolean, IsEmail, MaxLength, @@ -23,7 +23,7 @@ export class CreateGroupProfileDto { @ApiProperty({ enum: GROUP_TYPES, default: 'corporate' }) @IsOptional() - @IsEnum(GROUP_TYPES) + @IsIn(GROUP_TYPES) type?: string; @ApiPropertyOptional() diff --git a/apps/api/src/modules/groups/dto/list-blocks.dto.ts b/apps/api/src/modules/groups/dto/list-blocks.dto.ts index 3b0aa067..8f9044c7 100644 --- a/apps/api/src/modules/groups/dto/list-blocks.dto.ts +++ b/apps/api/src/modules/groups/dto/list-blocks.dto.ts @@ -1,4 +1,4 @@ -import { IsUUID, IsOptional, IsEnum, IsInt, Min, Max } from 'class-validator'; +import { IsUUID, IsOptional, IsIn, IsInt, Min, Max } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; @@ -16,7 +16,7 @@ export class ListBlocksDto { @ApiPropertyOptional({ enum: BLOCK_STATUSES }) @IsOptional() - @IsEnum(BLOCK_STATUSES) + @IsIn(BLOCK_STATUSES) status?: string; @ApiPropertyOptional({ default: 1 }) diff --git a/apps/api/src/modules/groups/dto/list-group-profiles.dto.ts b/apps/api/src/modules/groups/dto/list-group-profiles.dto.ts index 8d2cafc6..d4d7a94c 100644 --- a/apps/api/src/modules/groups/dto/list-group-profiles.dto.ts +++ b/apps/api/src/modules/groups/dto/list-group-profiles.dto.ts @@ -1,4 +1,4 @@ -import { IsUUID, IsOptional, IsEnum, IsInt, Min, Max } from 'class-validator'; +import { IsUUID, IsOptional, IsIn, IsInt, Min, Max } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; @@ -11,7 +11,7 @@ export class ListGroupProfilesDto { @ApiPropertyOptional({ enum: GROUP_TYPES }) @IsOptional() - @IsEnum(GROUP_TYPES) + @IsIn(GROUP_TYPES) type?: string; @ApiPropertyOptional({ default: 1 }) diff --git a/apps/api/src/modules/groups/dto/update-block.dto.ts b/apps/api/src/modules/groups/dto/update-block.dto.ts index b0b4a2dc..5651ccbc 100644 --- a/apps/api/src/modules/groups/dto/update-block.dto.ts +++ b/apps/api/src/modules/groups/dto/update-block.dto.ts @@ -1,7 +1,7 @@ import { IsString, IsOptional, - IsEnum, + IsIn, IsBoolean, IsInt, IsDateString, @@ -75,6 +75,6 @@ export class UpdateBlockDto { @ApiPropertyOptional({ enum: BLOCK_STATUSES }) @IsOptional() - @IsEnum(BLOCK_STATUSES) + @IsIn(BLOCK_STATUSES) status?: string; } diff --git a/apps/api/src/modules/groups/dto/update-group-profile.dto.ts b/apps/api/src/modules/groups/dto/update-group-profile.dto.ts index c83da602..a0364625 100644 --- a/apps/api/src/modules/groups/dto/update-group-profile.dto.ts +++ b/apps/api/src/modules/groups/dto/update-group-profile.dto.ts @@ -1,7 +1,7 @@ import { IsString, IsOptional, - IsEnum, + IsIn, IsEmail, MaxLength, } from 'class-validator'; @@ -18,7 +18,7 @@ export class UpdateGroupProfileDto { @ApiPropertyOptional({ enum: GROUP_TYPES }) @IsOptional() - @IsEnum(GROUP_TYPES) + @IsIn(GROUP_TYPES) type?: string; @ApiPropertyOptional() diff --git a/apps/api/src/modules/guest/dto/create-guest.dto.ts b/apps/api/src/modules/guest/dto/create-guest.dto.ts index 7b0b3bc9..ea033fee 100644 --- a/apps/api/src/modules/guest/dto/create-guest.dto.ts +++ b/apps/api/src/modules/guest/dto/create-guest.dto.ts @@ -4,7 +4,7 @@ import { IsOptional, IsEmail, IsBoolean, - IsEnum, + IsIn, IsDateString, IsObject, MaxLength, @@ -131,7 +131,7 @@ export class CreateGuestDto { @ApiPropertyOptional({ enum: ['none', 'silver', 'gold', 'platinum', 'diamond'], default: 'none' }) @IsOptional() - @IsEnum(['none', 'silver', 'gold', 'platinum', 'diamond']) + @IsIn(['none', 'silver', 'gold', 'platinum', 'diamond']) vipLevel?: string; @ApiPropertyOptional() diff --git a/apps/api/src/modules/guest/dto/search-guests.dto.ts b/apps/api/src/modules/guest/dto/search-guests.dto.ts index 94bc0dc2..4ccd45b9 100644 --- a/apps/api/src/modules/guest/dto/search-guests.dto.ts +++ b/apps/api/src/modules/guest/dto/search-guests.dto.ts @@ -1,4 +1,4 @@ -import { IsOptional, IsString, IsEnum, IsBoolean, IsInt, Min, Max } from 'class-validator'; +import { IsOptional, IsString, IsIn, IsBoolean, IsInt, Min, Max } from 'class-validator'; import { ApiPropertyOptional } from '@nestjs/swagger'; import { Transform, Type } from 'class-transformer'; @@ -22,7 +22,7 @@ export class SearchGuestsDto { @ApiPropertyOptional({ enum: ['none', 'silver', 'gold', 'platinum', 'diamond'] }) @IsOptional() - @IsEnum(['none', 'silver', 'gold', 'platinum', 'diamond']) + @IsIn(['none', 'silver', 'gold', 'platinum', 'diamond']) vipLevel?: string; @ApiPropertyOptional() diff --git a/apps/api/src/modules/house-account/dto/add-house-account-charge.dto.ts b/apps/api/src/modules/house-account/dto/add-house-account-charge.dto.ts index c0f79c94..9ee051d2 100644 --- a/apps/api/src/modules/house-account/dto/add-house-account-charge.dto.ts +++ b/apps/api/src/modules/house-account/dto/add-house-account-charge.dto.ts @@ -3,7 +3,7 @@ import { IsNotEmpty, IsOptional, IsUUID, - IsEnum, + IsIn, MaxLength, } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; @@ -35,7 +35,7 @@ export class AddHouseAccountChargeDto { description: 'House-account charges post to non-room revenue categories (KB 13.4)', }) @IsOptional() - @IsEnum(CHARGE_TYPES) + @IsIn(CHARGE_TYPES) type?: string; @ApiProperty({ example: 'Bottle of water' }) diff --git a/apps/api/src/modules/house-account/dto/add-house-account-payment.dto.ts b/apps/api/src/modules/house-account/dto/add-house-account-payment.dto.ts index f3c68119..c587208d 100644 --- a/apps/api/src/modules/house-account/dto/add-house-account-payment.dto.ts +++ b/apps/api/src/modules/house-account/dto/add-house-account-payment.dto.ts @@ -3,7 +3,7 @@ import { IsNotEmpty, IsOptional, IsUUID, - IsEnum, + IsIn, MaxLength, } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; @@ -26,7 +26,7 @@ export class AddHouseAccountPaymentDto { propertyId!: string; @ApiProperty({ enum: PAYMENT_METHODS, example: 'cash' }) - @IsEnum(PAYMENT_METHODS) + @IsIn(PAYMENT_METHODS) method!: string; @ApiProperty({ example: '12.50' }) diff --git a/apps/api/src/modules/house-account/dto/list-house-accounts.dto.ts b/apps/api/src/modules/house-account/dto/list-house-accounts.dto.ts index 0e247e6e..bbc7579d 100644 --- a/apps/api/src/modules/house-account/dto/list-house-accounts.dto.ts +++ b/apps/api/src/modules/house-account/dto/list-house-accounts.dto.ts @@ -1,4 +1,4 @@ -import { IsOptional, IsUUID, IsEnum, IsInt, Min, Max } from 'class-validator'; +import { IsOptional, IsUUID, IsIn, IsInt, Min, Max } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; @@ -9,12 +9,12 @@ export class ListHouseAccountsDto { @ApiPropertyOptional({ enum: ['retail', 'vendor', 'internal', 'other'] }) @IsOptional() - @IsEnum(['retail', 'vendor', 'internal', 'other']) + @IsIn(['retail', 'vendor', 'internal', 'other']) kind?: string; @ApiPropertyOptional({ enum: ['open', 'closed'] }) @IsOptional() - @IsEnum(['open', 'closed']) + @IsIn(['open', 'closed']) status?: string; @ApiPropertyOptional({ default: 1 }) diff --git a/apps/api/src/modules/house-account/dto/open-house-account.dto.ts b/apps/api/src/modules/house-account/dto/open-house-account.dto.ts index 6fdec1ee..da42e56e 100644 --- a/apps/api/src/modules/house-account/dto/open-house-account.dto.ts +++ b/apps/api/src/modules/house-account/dto/open-house-account.dto.ts @@ -3,7 +3,7 @@ import { IsNotEmpty, IsOptional, IsUUID, - IsEnum, + IsIn, MaxLength, } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; @@ -22,7 +22,7 @@ export class OpenHouseAccountDto { @ApiPropertyOptional({ enum: ['retail', 'vendor', 'internal', 'other'], default: 'retail' }) @IsOptional() - @IsEnum(['retail', 'vendor', 'internal', 'other']) + @IsIn(['retail', 'vendor', 'internal', 'other']) kind?: string; @ApiProperty({ example: 'USD' }) diff --git a/apps/api/src/modules/house-account/dto/sell-product.dto.ts b/apps/api/src/modules/house-account/dto/sell-product.dto.ts index 766970fc..047c9dc4 100644 --- a/apps/api/src/modules/house-account/dto/sell-product.dto.ts +++ b/apps/api/src/modules/house-account/dto/sell-product.dto.ts @@ -3,7 +3,7 @@ import { IsNotEmpty, IsOptional, IsUUID, - IsEnum, + IsIn, IsInt, Min, } from 'class-validator'; @@ -43,6 +43,6 @@ export class SellProductDto { description: 'If provided, take payment for the sale immediately (KB 13.3)', }) @IsOptional() - @IsEnum(PAYMENT_METHODS) + @IsIn(PAYMENT_METHODS) paymentMethod?: string; } diff --git a/apps/api/src/modules/housekeeping/dto/create-task.dto.ts b/apps/api/src/modules/housekeeping/dto/create-task.dto.ts index 47526757..de24f791 100644 --- a/apps/api/src/modules/housekeeping/dto/create-task.dto.ts +++ b/apps/api/src/modules/housekeeping/dto/create-task.dto.ts @@ -1,6 +1,6 @@ import { IsUUID, - IsEnum, + IsIn, IsOptional, IsInt, IsDateString, @@ -39,7 +39,7 @@ export class CreateTaskDto { roomId!: string; @ApiProperty({ enum: TASK_TYPES }) - @IsEnum(TASK_TYPES) + @IsIn(TASK_TYPES) type!: string; @ApiPropertyOptional({ default: 0 }) diff --git a/apps/api/src/modules/housekeeping/dto/list-tasks.dto.ts b/apps/api/src/modules/housekeeping/dto/list-tasks.dto.ts index 507d6e09..cf50fd6b 100644 --- a/apps/api/src/modules/housekeeping/dto/list-tasks.dto.ts +++ b/apps/api/src/modules/housekeeping/dto/list-tasks.dto.ts @@ -1,4 +1,4 @@ -import { IsUUID, IsOptional, IsEnum, IsDateString, IsInt, Min, Max } from 'class-validator'; +import { IsUUID, IsOptional, IsIn, IsDateString, IsInt, Min, Max } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; @@ -12,12 +12,12 @@ export class ListTasksDto { @ApiPropertyOptional({ enum: TASK_STATUSES }) @IsOptional() - @IsEnum(TASK_STATUSES) + @IsIn(TASK_STATUSES) status?: string; @ApiPropertyOptional({ enum: TASK_TYPES }) @IsOptional() - @IsEnum(TASK_TYPES) + @IsIn(TASK_TYPES) type?: string; @ApiPropertyOptional() diff --git a/apps/api/src/modules/ical/dto/ical.dto.ts b/apps/api/src/modules/ical/dto/ical.dto.ts index 0ad651cb..e3d281cb 100644 --- a/apps/api/src/modules/ical/dto/ical.dto.ts +++ b/apps/api/src/modules/ical/dto/ical.dto.ts @@ -1,7 +1,7 @@ import { IsBoolean, IsDateString, - IsEnum, + IsIn, IsOptional, IsString, IsUUID, @@ -22,7 +22,7 @@ export class CreateIcalFeedDto { roomTypeId!: string; @ApiProperty({ enum: ICAL_FEED_DIRECTIONS }) - @IsEnum(ICAL_FEED_DIRECTIONS) + @IsIn(ICAL_FEED_DIRECTIONS) direction!: (typeof ICAL_FEED_DIRECTIONS)[number]; @ApiProperty({ example: 'Airbnb Standard King calendar' }) @@ -66,7 +66,7 @@ export class ListIcalFeedsDto { @ApiPropertyOptional({ enum: ICAL_FEED_DIRECTIONS }) @IsOptional() - @IsEnum(ICAL_FEED_DIRECTIONS) + @IsIn(ICAL_FEED_DIRECTIONS) direction?: (typeof ICAL_FEED_DIRECTIONS)[number]; } diff --git a/apps/api/src/modules/lost-and-found/dto/lost-and-found.dto.ts b/apps/api/src/modules/lost-and-found/dto/lost-and-found.dto.ts index 2cdf71fd..b5de9c69 100644 --- a/apps/api/src/modules/lost-and-found/dto/lost-and-found.dto.ts +++ b/apps/api/src/modules/lost-and-found/dto/lost-and-found.dto.ts @@ -2,7 +2,7 @@ import { IsUUID, IsOptional, IsString, - IsEnum, + IsIn, IsDateString, } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; @@ -32,7 +32,7 @@ export class CreateLostAndFoundItemDto { @ApiPropertyOptional({ enum: CATEGORIES, default: 'general' }) @IsOptional() - @IsEnum(CATEGORIES) + @IsIn(CATEGORIES) category?: (typeof CATEGORIES)[number]; @ApiProperty() @@ -73,12 +73,12 @@ export class UpdateLostAndFoundItemDto { @ApiPropertyOptional({ enum: STATUSES }) @IsOptional() - @IsEnum(STATUSES) + @IsIn(STATUSES) status?: string; @ApiPropertyOptional({ enum: CATEGORIES }) @IsOptional() - @IsEnum(CATEGORIES) + @IsIn(CATEGORIES) category?: (typeof CATEGORIES)[number]; @ApiPropertyOptional() @@ -94,11 +94,11 @@ export class ListLostAndFoundItemsDto { @ApiPropertyOptional({ enum: STATUSES }) @IsOptional() - @IsEnum(STATUSES) + @IsIn(STATUSES) status?: string; @ApiPropertyOptional({ enum: CATEGORIES }) @IsOptional() - @IsEnum(CATEGORIES) + @IsIn(CATEGORIES) category?: (typeof CATEGORIES)[number]; } diff --git a/apps/api/src/modules/media/dto/create-media.dto.ts b/apps/api/src/modules/media/dto/create-media.dto.ts index c86dedaa..717ee9c2 100644 --- a/apps/api/src/modules/media/dto/create-media.dto.ts +++ b/apps/api/src/modules/media/dto/create-media.dto.ts @@ -3,7 +3,7 @@ import { IsString, IsNotEmpty, IsOptional, - IsEnum, + IsIn, IsInt, IsBoolean, MaxLength, @@ -28,7 +28,7 @@ export class CreateMediaDto { propertyId!: string; @ApiProperty({ enum: MEDIA_OWNER_TYPES }) - @IsEnum(MEDIA_OWNER_TYPES) + @IsIn(MEDIA_OWNER_TYPES) ownerType!: (typeof MEDIA_OWNER_TYPES)[number]; @ApiProperty({ format: 'uuid', description: 'property / room_type / room id' }) @@ -42,7 +42,7 @@ export class CreateMediaDto { @ApiPropertyOptional({ enum: MEDIA_CATEGORIES, default: 'other' }) @IsOptional() - @IsEnum(MEDIA_CATEGORIES) + @IsIn(MEDIA_CATEGORIES) category?: (typeof MEDIA_CATEGORIES)[number]; @ApiPropertyOptional() diff --git a/apps/api/src/modules/media/dto/query-media.dto.ts b/apps/api/src/modules/media/dto/query-media.dto.ts index 088087b3..5648e386 100644 --- a/apps/api/src/modules/media/dto/query-media.dto.ts +++ b/apps/api/src/modules/media/dto/query-media.dto.ts @@ -1,4 +1,4 @@ -import { IsUUID, IsEnum } from 'class-validator'; +import { IsUUID, IsIn } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; import { MEDIA_OWNER_TYPES } from './create-media.dto'; @@ -12,7 +12,7 @@ export class QueryMediaDto { propertyId!: string; @ApiProperty({ enum: MEDIA_OWNER_TYPES }) - @IsEnum(MEDIA_OWNER_TYPES) + @IsIn(MEDIA_OWNER_TYPES) ownerType!: (typeof MEDIA_OWNER_TYPES)[number]; @ApiProperty({ format: 'uuid' }) diff --git a/apps/api/src/modules/media/dto/reorder-media.dto.ts b/apps/api/src/modules/media/dto/reorder-media.dto.ts index 4999005b..755a658c 100644 --- a/apps/api/src/modules/media/dto/reorder-media.dto.ts +++ b/apps/api/src/modules/media/dto/reorder-media.dto.ts @@ -1,4 +1,4 @@ -import { IsUUID, IsEnum, IsArray, ArrayNotEmpty } from 'class-validator'; +import { IsUUID, IsIn, IsArray, ArrayNotEmpty } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; import { MEDIA_OWNER_TYPES } from './create-media.dto'; @@ -8,7 +8,7 @@ export class ReorderMediaDto { propertyId!: string; @ApiProperty({ enum: MEDIA_OWNER_TYPES }) - @IsEnum(MEDIA_OWNER_TYPES) + @IsIn(MEDIA_OWNER_TYPES) ownerType!: (typeof MEDIA_OWNER_TYPES)[number]; @ApiProperty({ format: 'uuid' }) diff --git a/apps/api/src/modules/media/dto/update-media.dto.ts b/apps/api/src/modules/media/dto/update-media.dto.ts index dd6d944a..c2c612d3 100644 --- a/apps/api/src/modules/media/dto/update-media.dto.ts +++ b/apps/api/src/modules/media/dto/update-media.dto.ts @@ -1,7 +1,7 @@ import { IsString, IsOptional, - IsEnum, + IsIn, IsInt, IsBoolean, IsUrl, @@ -20,7 +20,7 @@ export class UpdateMediaDto { @ApiPropertyOptional({ enum: MEDIA_CATEGORIES }) @IsOptional() - @IsEnum(MEDIA_CATEGORIES) + @IsIn(MEDIA_CATEGORIES) category?: (typeof MEDIA_CATEGORIES)[number]; @ApiPropertyOptional() diff --git a/apps/api/src/modules/media/dto/upload-media.dto.ts b/apps/api/src/modules/media/dto/upload-media.dto.ts index c83efb44..cbee7d2e 100644 --- a/apps/api/src/modules/media/dto/upload-media.dto.ts +++ b/apps/api/src/modules/media/dto/upload-media.dto.ts @@ -2,7 +2,7 @@ import { IsUUID, IsString, IsOptional, - IsEnum, + IsIn, MaxLength, } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; @@ -18,7 +18,7 @@ export class UploadMediaDto { propertyId!: string; @ApiProperty({ enum: MEDIA_OWNER_TYPES }) - @IsEnum(MEDIA_OWNER_TYPES) + @IsIn(MEDIA_OWNER_TYPES) ownerType!: (typeof MEDIA_OWNER_TYPES)[number]; @ApiProperty({ format: 'uuid' }) @@ -27,7 +27,7 @@ export class UploadMediaDto { @ApiPropertyOptional({ enum: MEDIA_CATEGORIES, default: 'other' }) @IsOptional() - @IsEnum(MEDIA_CATEGORIES) + @IsIn(MEDIA_CATEGORIES) category?: (typeof MEDIA_CATEGORIES)[number]; @ApiPropertyOptional() diff --git a/apps/api/src/modules/payment/dto/correct-payment.dto.ts b/apps/api/src/modules/payment/dto/correct-payment.dto.ts index 7f147ba3..89a63a62 100644 --- a/apps/api/src/modules/payment/dto/correct-payment.dto.ts +++ b/apps/api/src/modules/payment/dto/correct-payment.dto.ts @@ -1,4 +1,4 @@ -import { IsNotEmpty, IsOptional, IsUUID, IsEnum } from 'class-validator'; +import { IsNotEmpty, IsOptional, IsUUID, IsIn } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; /** @@ -16,6 +16,6 @@ export class CorrectPaymentDto { description: 'Optional op override; must be the legal op for the payment state', }) @IsOptional() - @IsEnum(['void', 'refund', 'adjust']) + @IsIn(['void', 'refund', 'adjust']) op?: 'void' | 'refund' | 'adjust'; } diff --git a/apps/api/src/modules/payment/dto/create-payment.dto.ts b/apps/api/src/modules/payment/dto/create-payment.dto.ts index 5911e4d8..30c0f71d 100644 --- a/apps/api/src/modules/payment/dto/create-payment.dto.ts +++ b/apps/api/src/modules/payment/dto/create-payment.dto.ts @@ -3,7 +3,7 @@ import { IsNotEmpty, IsOptional, IsUUID, - IsEnum, + IsIn, IsDateString, MaxLength, } from 'class-validator'; @@ -35,7 +35,7 @@ export class CreatePaymentDto { description: 'Manual settle tender. Use credit_card/debit_card here for offline card machines (no gateway). Gateway cards must use POST /payments/authorize. pix = Brazil PIX paid direct to the property.', }) - @IsEnum([ + @IsIn([ 'credit_card', 'debit_card', 'cash', diff --git a/apps/api/src/modules/payment/dto/list-payments.dto.ts b/apps/api/src/modules/payment/dto/list-payments.dto.ts index 0b6f52fc..0a209f00 100644 --- a/apps/api/src/modules/payment/dto/list-payments.dto.ts +++ b/apps/api/src/modules/payment/dto/list-payments.dto.ts @@ -1,4 +1,4 @@ -import { IsOptional, IsUUID, IsEnum, IsInt, Min, Max } from 'class-validator'; +import { IsOptional, IsUUID, IsIn, IsInt, Min, Max } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; @@ -14,7 +14,7 @@ export class ListPaymentsDto { @ApiPropertyOptional({ enum: ['pending', 'authorized', 'captured', 'settled', 'refunded', 'partially_refunded', 'failed', 'voided'] }) @IsOptional() - @IsEnum(['pending', 'authorized', 'captured', 'settled', 'refunded', 'partially_refunded', 'failed', 'voided']) + @IsIn(['pending', 'authorized', 'captured', 'settled', 'refunded', 'partially_refunded', 'failed', 'voided']) status?: string; @ApiPropertyOptional({ @@ -30,7 +30,7 @@ export class ListPaymentsDto { ], }) @IsOptional() - @IsEnum([ + @IsIn([ 'credit_card', 'debit_card', 'cash', diff --git a/apps/api/src/modules/policy/dto/create-cancellation-policy.dto.ts b/apps/api/src/modules/policy/dto/create-cancellation-policy.dto.ts index a90bd8b5..5e50b51f 100644 --- a/apps/api/src/modules/policy/dto/create-cancellation-policy.dto.ts +++ b/apps/api/src/modules/policy/dto/create-cancellation-policy.dto.ts @@ -4,7 +4,7 @@ import { IsOptional, IsUUID, IsBoolean, - IsEnum, + IsIn, IsInt, IsNumberString, MaxLength, @@ -58,7 +58,7 @@ export class CreateCancellationPolicyDto { @ApiPropertyOptional({ enum: CANCELLATION_PENALTY_TYPES, default: 'first_night' }) @IsOptional() - @IsEnum(CANCELLATION_PENALTY_TYPES) + @IsIn(CANCELLATION_PENALTY_TYPES) penaltyType?: (typeof CANCELLATION_PENALTY_TYPES)[number]; @ApiPropertyOptional({ example: '50.00', description: 'Required when penaltyType=percentage' }) @@ -71,7 +71,7 @@ export class CreateCancellationPolicyDto { default: 'refund_if_refundable', }) @IsOptional() - @IsEnum(CANCELLATION_DEPOSIT_HANDLINGS) + @IsIn(CANCELLATION_DEPOSIT_HANDLINGS) depositHandling?: (typeof CANCELLATION_DEPOSIT_HANDLINGS)[number]; @ApiPropertyOptional({ default: true }) diff --git a/apps/api/src/modules/pos/dto/post-pos-charge.dto.ts b/apps/api/src/modules/pos/dto/post-pos-charge.dto.ts index 699cbbec..bd6ba31e 100644 --- a/apps/api/src/modules/pos/dto/post-pos-charge.dto.ts +++ b/apps/api/src/modules/pos/dto/post-pos-charge.dto.ts @@ -3,7 +3,7 @@ import { IsNotEmpty, IsOptional, IsUUID, - IsEnum, + IsIn, IsDateString, MaxLength, } from 'class-validator'; @@ -43,7 +43,7 @@ export class PostPosChargeDto { folioId!: string; @ApiProperty({ enum: POS_CHARGE_TYPES, example: 'food_beverage' }) - @IsEnum(POS_CHARGE_TYPES) + @IsIn(POS_CHARGE_TYPES) type!: (typeof POS_CHARGE_TYPES)[number]; @ApiProperty({ example: 'Dinner — Oceanfront Grill (check #4821)' }) diff --git a/apps/api/src/modules/rate-plan/dto/create-rate-plan.dto.ts b/apps/api/src/modules/rate-plan/dto/create-rate-plan.dto.ts index b4311883..50603432 100644 --- a/apps/api/src/modules/rate-plan/dto/create-rate-plan.dto.ts +++ b/apps/api/src/modules/rate-plan/dto/create-rate-plan.dto.ts @@ -3,7 +3,7 @@ import { IsNotEmpty, IsOptional, IsUUID, - IsEnum, + IsIn, IsBoolean, IsInt, IsNumber, @@ -49,7 +49,7 @@ export class CreateRatePlanDto { description?: string; @ApiProperty({ enum: ['bar', 'derived', 'negotiated', 'package', 'promotional'] }) - @IsEnum(['bar', 'derived', 'negotiated', 'package', 'promotional']) + @IsIn(['bar', 'derived', 'negotiated', 'package', 'promotional']) type!: string; @ApiProperty({ example: '199.99' }) @@ -71,7 +71,7 @@ export class CreateRatePlanDto { @ApiPropertyOptional({ enum: ['percentage', 'fixed'] }) @IsOptional() - @IsEnum(['percentage', 'fixed']) + @IsIn(['percentage', 'fixed']) @ValidateIf((o) => o.type === 'derived') derivedAdjustmentType?: string; @@ -88,7 +88,7 @@ export class CreateRatePlanDto { @ApiPropertyOptional({ enum: ['room_only', 'breakfast', 'half_board', 'full_board', 'all_inclusive'] }) @IsOptional() - @IsEnum(['room_only', 'breakfast', 'half_board', 'full_board', 'all_inclusive']) + @IsIn(['room_only', 'breakfast', 'half_board', 'full_board', 'all_inclusive']) mealPlan?: string; @ApiPropertyOptional({ example: '2024-01-01' }) diff --git a/apps/api/src/modules/rate-plan/dto/rate-adjustment.dto.ts b/apps/api/src/modules/rate-plan/dto/rate-adjustment.dto.ts index 72662431..2b3b7106 100644 --- a/apps/api/src/modules/rate-plan/dto/rate-adjustment.dto.ts +++ b/apps/api/src/modules/rate-plan/dto/rate-adjustment.dto.ts @@ -1,9 +1,9 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsEnum, IsNumber, IsInt, Min, Max } from 'class-validator'; +import { IsIn, IsNumber, IsInt, Min, Max } from 'class-validator'; export class RateAdjustmentRuleDto { @ApiProperty({ enum: ['percentage', 'fixed'] }) - @IsEnum(['percentage', 'fixed']) + @IsIn(['percentage', 'fixed']) adjustmentType!: 'percentage' | 'fixed'; @ApiProperty({ description: 'Negative = discount, positive = surcharge' }) diff --git a/apps/api/src/modules/reservation/dto/bulk-action.dto.ts b/apps/api/src/modules/reservation/dto/bulk-action.dto.ts index 71fb372f..fcce0b4b 100644 --- a/apps/api/src/modules/reservation/dto/bulk-action.dto.ts +++ b/apps/api/src/modules/reservation/dto/bulk-action.dto.ts @@ -1,7 +1,7 @@ import { IsArray, IsUUID, - IsEnum, + IsIn, IsOptional, IsString, ArrayMinSize, @@ -19,7 +19,7 @@ export class BulkActionDto { description: 'Action to apply to each reservation', enum: ['check_in', 'check_out', 'cancel'], }) - @IsEnum(['check_in', 'check_out', 'cancel']) + @IsIn(['check_in', 'check_out', 'cancel']) action!: 'check_in' | 'check_out' | 'cancel'; @ApiPropertyOptional({ description: 'Reason — used as cancellation reason for the cancel action' }) diff --git a/apps/api/src/modules/reservation/dto/create-reservation.dto.ts b/apps/api/src/modules/reservation/dto/create-reservation.dto.ts index 227941fa..814326f7 100644 --- a/apps/api/src/modules/reservation/dto/create-reservation.dto.ts +++ b/apps/api/src/modules/reservation/dto/create-reservation.dto.ts @@ -4,7 +4,7 @@ import { IsInt, IsOptional, IsString, - IsEnum, + IsIn, Min, MaxLength, } from 'class-validator'; @@ -63,7 +63,7 @@ export class CreateReservationDto { specialRequests?: string; @ApiProperty({ enum: ['direct', 'ota', 'gds', 'phone', 'walk_in', 'agent', 'group', 'corporate'] }) - @IsEnum(['direct', 'ota', 'gds', 'phone', 'walk_in', 'agent', 'group', 'corporate']) + @IsIn(['direct', 'ota', 'gds', 'phone', 'walk_in', 'agent', 'group', 'corporate']) source!: string; @ApiPropertyOptional({ example: 'booking_com' }) diff --git a/apps/api/src/modules/reservation/dto/import-reservations.dto.ts b/apps/api/src/modules/reservation/dto/import-reservations.dto.ts index 4197cda0..f1aa8464 100644 --- a/apps/api/src/modules/reservation/dto/import-reservations.dto.ts +++ b/apps/api/src/modules/reservation/dto/import-reservations.dto.ts @@ -8,7 +8,7 @@ import { IsBoolean, Min, MaxLength, - IsEnum, + IsIn, ValidateNested, ArrayMinSize, } from 'class-validator'; @@ -74,7 +74,7 @@ export class CreateReservationRow { currencyCode!: string; @ApiProperty({ enum: ['direct', 'ota', 'gds', 'phone', 'walk_in', 'agent', 'group', 'corporate'] }) - @IsEnum(['direct', 'ota', 'gds', 'phone', 'walk_in', 'agent', 'group', 'corporate']) + @IsIn(['direct', 'ota', 'gds', 'phone', 'walk_in', 'agent', 'group', 'corporate']) source!: string; @ApiPropertyOptional({ default: 1 }) diff --git a/apps/api/src/modules/reservation/dto/list-reservations.dto.ts b/apps/api/src/modules/reservation/dto/list-reservations.dto.ts index b40e646b..38da78f7 100644 --- a/apps/api/src/modules/reservation/dto/list-reservations.dto.ts +++ b/apps/api/src/modules/reservation/dto/list-reservations.dto.ts @@ -1,4 +1,4 @@ -import { IsUUID, IsOptional, IsEnum, IsDateString, IsInt, Min, Max, IsString } from 'class-validator'; +import { IsUUID, IsOptional, IsIn, IsDateString, IsInt, Min, Max, IsString } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; @@ -21,7 +21,7 @@ export class ListReservationsDto { @ApiPropertyOptional({ enum: RESERVATION_STATUSES }) @IsOptional() - @IsEnum(RESERVATION_STATUSES) + @IsIn(RESERVATION_STATUSES) status?: string; @ApiPropertyOptional({ diff --git a/apps/api/src/modules/room/dto/hk-observation.dto.ts b/apps/api/src/modules/room/dto/hk-observation.dto.ts index 7939a87d..b95a9c21 100644 --- a/apps/api/src/modules/room/dto/hk-observation.dto.ts +++ b/apps/api/src/modules/room/dto/hk-observation.dto.ts @@ -1,4 +1,4 @@ -import { IsEnum, IsInt, IsOptional, IsUUID, Min } from 'class-validator'; +import { IsIn, IsInt, IsOptional, IsUUID, Min } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; @@ -6,7 +6,7 @@ const OCCUPANCY = ['unknown', 'vacant', 'occupied'] as const; export class HkObservationDto { @ApiProperty({ enum: OCCUPANCY }) - @IsEnum(OCCUPANCY) + @IsIn(OCCUPANCY) occupancy!: (typeof OCCUPANCY)[number]; @ApiPropertyOptional() diff --git a/apps/api/src/modules/service-requests/dto/service-request.dto.ts b/apps/api/src/modules/service-requests/dto/service-request.dto.ts index 242b2923..bfc41ee0 100644 --- a/apps/api/src/modules/service-requests/dto/service-request.dto.ts +++ b/apps/api/src/modules/service-requests/dto/service-request.dto.ts @@ -2,7 +2,7 @@ import { IsUUID, IsOptional, IsString, - IsEnum, + IsIn, IsInt, } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; @@ -36,7 +36,7 @@ export class CreateServiceRequestDto { reservationId?: string; @ApiProperty({ enum: TYPES }) - @IsEnum(TYPES) + @IsIn(TYPES) type!: string; @ApiPropertyOptional({ default: 0 }) @@ -73,7 +73,7 @@ export class UpdateServiceRequestDto { @ApiPropertyOptional({ enum: TYPES }) @IsOptional() - @IsEnum(TYPES) + @IsIn(TYPES) type?: string; @ApiPropertyOptional() @@ -84,7 +84,7 @@ export class UpdateServiceRequestDto { @ApiPropertyOptional({ enum: STATUSES }) @IsOptional() - @IsEnum(STATUSES) + @IsIn(STATUSES) status?: string; @ApiPropertyOptional() @@ -105,12 +105,12 @@ export class ListServiceRequestsDto { @ApiPropertyOptional({ enum: STATUSES }) @IsOptional() - @IsEnum(STATUSES) + @IsIn(STATUSES) status?: string; @ApiPropertyOptional({ enum: TYPES }) @IsOptional() - @IsEnum(TYPES) + @IsIn(TYPES) type?: string; } diff --git a/apps/api/src/modules/tax/dto/create-tax-rule.dto.ts b/apps/api/src/modules/tax/dto/create-tax-rule.dto.ts index 9ba84a28..9909569d 100644 --- a/apps/api/src/modules/tax/dto/create-tax-rule.dto.ts +++ b/apps/api/src/modules/tax/dto/create-tax-rule.dto.ts @@ -6,7 +6,7 @@ import { IsArray, IsDateString, IsObject, - IsEnum, + IsIn, IsInt, ValidateIf, Min, @@ -20,7 +20,7 @@ export class CreateTaxRuleDto { @IsString() code!: string; - @IsEnum(['percentage', 'flat_per_night', 'flat_per_stay', 'split_component']) + @IsIn(['percentage', 'flat_per_night', 'flat_per_stay', 'split_component']) type!: 'percentage' | 'flat_per_night' | 'flat_per_stay' | 'split_component'; @IsString() diff --git a/apps/api/src/modules/tax/dto/update-tax-rule.dto.ts b/apps/api/src/modules/tax/dto/update-tax-rule.dto.ts index 3821f77d..d40487b4 100644 --- a/apps/api/src/modules/tax/dto/update-tax-rule.dto.ts +++ b/apps/api/src/modules/tax/dto/update-tax-rule.dto.ts @@ -6,7 +6,7 @@ import { IsArray, IsDateString, IsObject, - IsEnum, + IsIn, IsInt, ValidateIf, Min, @@ -22,7 +22,7 @@ export class UpdateTaxRuleDto { @IsOptional() code?: string; - @IsEnum(['percentage', 'flat_per_night', 'flat_per_stay', 'split_component']) + @IsIn(['percentage', 'flat_per_night', 'flat_per_stay', 'split_component']) @IsOptional() type?: 'percentage' | 'flat_per_night' | 'flat_per_stay' | 'split_component'; diff --git a/apps/api/src/modules/turnaways/dto/turnaways.dto.ts b/apps/api/src/modules/turnaways/dto/turnaways.dto.ts index 3b4e9175..4b6452a9 100644 --- a/apps/api/src/modules/turnaways/dto/turnaways.dto.ts +++ b/apps/api/src/modules/turnaways/dto/turnaways.dto.ts @@ -1,7 +1,7 @@ import { IsBoolean, IsDateString, - IsEnum, + IsIn, IsInt, IsNotEmpty, IsOptional, @@ -29,7 +29,7 @@ export class CreateTurnawayReasonCodeDto { description!: string; @ApiProperty({ enum: TURNAWAY_TYPES }) - @IsEnum(TURNAWAY_TYPES) + @IsIn(TURNAWAY_TYPES) type!: (typeof TURNAWAY_TYPES)[number]; @ApiPropertyOptional({ default: true }) @@ -89,7 +89,7 @@ export class CreateTurnawayDto { reasonCodeId?: string; @ApiProperty({ enum: TURNAWAY_TYPES }) - @IsEnum(TURNAWAY_TYPES) + @IsIn(TURNAWAY_TYPES) type!: (typeof TURNAWAY_TYPES)[number]; @ApiPropertyOptional({ example: 'phone' }) diff --git a/apps/api/src/modules/waitlist/dto/waitlist.dto.ts b/apps/api/src/modules/waitlist/dto/waitlist.dto.ts index 4af2b07f..d1f7fcb6 100644 --- a/apps/api/src/modules/waitlist/dto/waitlist.dto.ts +++ b/apps/api/src/modules/waitlist/dto/waitlist.dto.ts @@ -1,7 +1,7 @@ import { IsDateString, IsEmail, - IsEnum, + IsIn, IsInt, IsOptional, IsString, @@ -158,7 +158,7 @@ export class ListWaitlistEntriesDto { @ApiPropertyOptional({ enum: WAITLIST_STATUSES }) @IsOptional() - @IsEnum(WAITLIST_STATUSES) + @IsIn(WAITLIST_STATUSES) status?: (typeof WAITLIST_STATUSES)[number]; } diff --git a/apps/api/src/validation-messages.spec.ts b/apps/api/src/validation-messages.spec.ts new file mode 100644 index 00000000..a389f8f0 --- /dev/null +++ b/apps/api/src/validation-messages.spec.ts @@ -0,0 +1,118 @@ +/** + * Every 400 this API returns for a bad enum value must name the values it + * would have accepted. + * + * WHY THIS EXISTS. `@IsEnum(['a','b'])` reads correctly and validates + * correctly, but produces the message + * + * type must be one of the following values: + * + * with nothing after the colon. class-validator's `IsEnum` is for TypeScript + * enum OBJECTS: it validates with `Object.keys(entity).map(k => entity[k])`, + * which happens to read an array's values, but it builds its message from + * `Object.entries(entity).filter(([k]) => isNaN(parseInt(k)))`, which drops + * every key of an array because array keys are all numeric. So the check + * passes an array through and the message comes out empty. `@IsIn([...])` is + * the decorator for a list of allowed values, and interpolates the list. + * + * Every enum decorator in the API was affected -- 88 across 64 files -- so a + * client sending `type: "beverage"` was told only that it was wrong, never + * that `food_beverage` exists. + * + * THE TEST READS METADATA, NOT SOURCE. Grepping for the decorator would only + * find the spelling it was told to look for; class-validator's own registry + * holds what will actually be evaluated at runtime, including the copies + * PartialType and OmitType generate, which no grep sees. + */ +import 'reflect-metadata'; +import { describe, expect, it } from 'vitest'; +import { getMetadataStorage } from 'class-validator'; + +// Load every DTO so its decorators register. A file that is never imported +// contributes no metadata, which would make this test pass by not looking. +// `!**/*.spec.ts` matters: one DTO directory holds its own spec, and pulling +// it in here would run that file's `describe` blocks inside this one. +// Booking-requests lives in packages/ but its HTTP DTOs are still staff API +// 400 surfaces — include them so a future @IsEnum([...]) there cannot sneak +// past this guardrail. +const dtoModules = import.meta.glob( + [ + './modules/**/dto/**/*.ts', + '../../../packages/booking-requests/src/http/dto/**/*.ts', + '!**/*.spec.ts', + ], + { eager: true }, +); +interface Meta { + // `type` is 'customValidation' for EVERY decorator built on ValidateBy, + // which is all of them here. `name` is the discriminator. Filtering on + // `type === 'isEnum'` matches nothing and makes this file pass while the + // bug it exists to catch is present. + type?: string; + name?: string; + target?: { name?: string }; + propertyName?: string; + constraints?: unknown[]; +} + +function allMetadata(): Meta[] { + const storage = getMetadataStorage() as unknown as { + validationMetadatas: Map; + }; + const out: Meta[] = []; + for (const list of storage.validationMetadatas.values()) out.push(...list); + return out; +} + +const describeSite = (m: Meta) => `${m.target?.name ?? '?'}.${m.propertyName ?? '?'}`; + +describe('enum validation messages', () => { + it('loaded the DTOs it is meant to be checking', () => { + const loaded = Object.keys(dtoModules); + expect(loaded.length).toBeGreaterThan(50); + expect(loaded.some((path) => path.includes('booking-requests'))).toBe(true); + expect(allMetadata().length).toBeGreaterThan(1000); + // And is looking at constraints that exist: a filter that matches nothing + // is the way this file fails silently, so assert it matches plenty. + expect(allMetadata().filter((m) => m.name === 'isIn').length).toBeGreaterThan(50); + // Booking-requests list DTO must be in the registry (not only on disk). + expect( + allMetadata().some((m) => m.target?.name === 'ListBookingRequestsDto' && m.name === 'isIn'), + ).toBe(true); + }); + + it('never uses IsEnum with an array, whose message comes out empty', () => { + const broken = allMetadata() + .filter((m) => m.name === 'isEnum') + .filter((m) => !Array.isArray(m.constraints?.[1]) || (m.constraints[1] as unknown[]).length === 0) + .map(describeSite); + expect(broken).toEqual([]); + }); + + it('gives every isIn constraint a non-empty list of allowed values', () => { + const empty = allMetadata() + .filter((m) => m.name === 'isIn') + .filter((m) => !Array.isArray(m.constraints?.[0]) || (m.constraints[0] as unknown[]).length === 0) + .map(describeSite); + expect(empty).toEqual([]); + }); + + // The assertions above are about metadata. This one is about what a caller + // actually reads, so a future refactor cannot satisfy the shape while still + // producing an empty message. + it('names the allowed values in the rendered message', async () => { + const { validate } = await import('class-validator'); + const { CreateChargeDto } = await import('./modules/folio/dto/create-charge.dto'); + const dto = Object.assign(new CreateChargeDto(), { + folioId: '00000000-0000-4000-8000-000000000000', + type: 'beverage', + description: 'a drink', + amount: '1000', + currencyCode: 'JPY', + }); + const errors = await validate(dto, { skipMissingProperties: true }); + const message = Object.values(errors.find((e) => e.property === 'type')?.constraints ?? {}).join(' '); + expect(message).toContain('food_beverage'); + expect(message).not.toMatch(/values:\s*$/); + }); +}); diff --git a/docs/test-stats.json b/docs/test-stats.json index 91fba5a8..2336b1ef 100644 --- a/docs/test-stats.json +++ b/docs/test-stats.json @@ -1,7 +1,7 @@ { - "tests": 2245, - "files": 268, + "tests": 2249, + "files": 269, "scope": "all workspace packages with a test script", "semantics": "passed test cases and files containing at least one passed test; skipped test cases and skipped-only files are excluded", - "updatedAt": "2026-09-08T08:06:24.354Z" + "updatedAt": "2026-09-09T12:26:36.978Z" } diff --git a/packages/booking-requests/src/http/dto/accept-booking-request.dto.ts b/packages/booking-requests/src/http/dto/accept-booking-request.dto.ts index c95117f5..71b83acf 100644 --- a/packages/booking-requests/src/http/dto/accept-booking-request.dto.ts +++ b/packages/booking-requests/src/http/dto/accept-booking-request.dto.ts @@ -1,12 +1,12 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; -import { IsEnum, IsOptional, IsString, Matches, MaxLength } from 'class-validator'; +import { IsIn, IsOptional, IsString, Matches, MaxLength } from 'class-validator'; import { IsMoneyString } from '@telivityhaip/shared'; const BOOKING_REQUEST_PRICE_SOURCES = ['submitted', 'current', 'custom'] as const; export class AcceptBookingRequestDto { @ApiProperty({ enum: BOOKING_REQUEST_PRICE_SOURCES }) - @IsEnum(BOOKING_REQUEST_PRICE_SOURCES) + @IsIn(BOOKING_REQUEST_PRICE_SOURCES) priceSource!: (typeof BOOKING_REQUEST_PRICE_SOURCES)[number]; @ApiProperty({ description: 'Opaque fingerprint returned by the latest acceptance preview' }) diff --git a/packages/booking-requests/src/http/dto/amend-booking-request-stay.dto.ts b/packages/booking-requests/src/http/dto/amend-booking-request-stay.dto.ts index b68528bb..435fa387 100644 --- a/packages/booking-requests/src/http/dto/amend-booking-request-stay.dto.ts +++ b/packages/booking-requests/src/http/dto/amend-booking-request-stay.dto.ts @@ -1,5 +1,5 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; -import { IsEnum, IsOptional, IsString, IsUUID, Matches, MaxLength } from 'class-validator'; +import { IsIn, IsOptional, IsString, IsUUID, Matches, MaxLength } from 'class-validator'; import { IsMoneyString } from '@telivityhaip/shared'; import { IsCanonicalCalendarDate } from '@telivityhaip/shared'; @@ -23,7 +23,7 @@ export class PreviewBookingRequestStayAmendmentDto extends BookingRequestStayAme export class AmendBookingRequestStayDto extends BookingRequestStayAmendmentDatesDto { @ApiProperty({ enum: STAY_AMENDMENT_PRICE_SOURCES }) - @IsEnum(STAY_AMENDMENT_PRICE_SOURCES) + @IsIn(STAY_AMENDMENT_PRICE_SOURCES) priceSource!: (typeof STAY_AMENDMENT_PRICE_SOURCES)[number]; @ApiProperty({ description: 'Opaque fingerprint returned by the latest amendment preview' }) diff --git a/packages/booking-requests/src/http/dto/booking-request-payment.dto.ts b/packages/booking-requests/src/http/dto/booking-request-payment.dto.ts index b442986d..c27069b7 100644 --- a/packages/booking-requests/src/http/dto/booking-request-payment.dto.ts +++ b/packages/booking-requests/src/http/dto/booking-request-payment.dto.ts @@ -4,7 +4,7 @@ import { ArrayUnique, IsArray, IsDateString, - IsEnum, + IsIn, IsInt, IsNotEmpty, IsOptional, @@ -55,7 +55,7 @@ export class CreateBookingRequestInstallmentDto { percentage?: string; @ApiProperty({ enum: BOOKING_REQUEST_INSTALLMENT_MILESTONES }) - @IsEnum(BOOKING_REQUEST_INSTALLMENT_MILESTONES) + @IsIn(BOOKING_REQUEST_INSTALLMENT_MILESTONES) dueMilestone!: (typeof BOOKING_REQUEST_INSTALLMENT_MILESTONES)[number]; @ApiPropertyOptional({ example: '2026-09-01' }) @@ -111,7 +111,7 @@ export class RecordBookingRequestExternalPaymentDto { currencyCode!: string; @ApiProperty({ enum: BOOKING_REQUEST_EXTERNAL_PAYMENT_METHODS }) - @IsEnum(BOOKING_REQUEST_EXTERNAL_PAYMENT_METHODS) + @IsIn(BOOKING_REQUEST_EXTERNAL_PAYMENT_METHODS) method!: (typeof BOOKING_REQUEST_EXTERNAL_PAYMENT_METHODS)[number]; @ApiProperty({ description: 'When the externally collected money moved' }) diff --git a/packages/booking-requests/src/http/dto/list-booking-requests.dto.ts b/packages/booking-requests/src/http/dto/list-booking-requests.dto.ts index 72432812..8f14ba25 100644 --- a/packages/booking-requests/src/http/dto/list-booking-requests.dto.ts +++ b/packages/booking-requests/src/http/dto/list-booking-requests.dto.ts @@ -2,7 +2,7 @@ import { Transform, Type } from 'class-transformer'; import { IsBoolean, IsDateString, - IsEnum, + IsIn, IsInt, IsOptional, IsString, @@ -30,7 +30,7 @@ export class ListBookingRequestsDto { @ApiPropertyOptional({ enum: BOOKING_REQUEST_STATUSES }) @IsOptional() - @IsEnum(BOOKING_REQUEST_STATUSES) + @IsIn(BOOKING_REQUEST_STATUSES) status?: (typeof BOOKING_REQUEST_STATUSES)[number]; @ApiPropertyOptional() @@ -67,12 +67,12 @@ export class ListBookingRequestsDto { @ApiPropertyOptional({ enum: BOOKING_REQUEST_SORT_FIELDS, default: 'createdAt' }) @IsOptional() - @IsEnum(BOOKING_REQUEST_SORT_FIELDS) + @IsIn(BOOKING_REQUEST_SORT_FIELDS) sortBy?: (typeof BOOKING_REQUEST_SORT_FIELDS)[number] = 'createdAt'; @ApiPropertyOptional({ enum: BOOKING_REQUEST_SORT_ORDERS, default: 'desc' }) @IsOptional() - @IsEnum(BOOKING_REQUEST_SORT_ORDERS) + @IsIn(BOOKING_REQUEST_SORT_ORDERS) sortOrder?: (typeof BOOKING_REQUEST_SORT_ORDERS)[number] = 'desc'; @ApiPropertyOptional({ default: 1 })