@@ -2494,7 +2494,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
24942494 . expect ( 400 ) ;
24952495
24962496 expect ( response . body . error . message ) . toEqual (
2497- `Missing attendee phone number - it is required by the event type. Pass it as \ "attendee.phoneNumber\ " string in the request.`
2497+ `Missing attendee phone number - it is required by the event type. Pass it as "attendee.phoneNumber" string in the request.`
24982498 ) ;
24992499 } ) ;
25002500
@@ -3026,13 +3026,154 @@ describe("Bookings Endpoints 2024-08-13", () => {
30263026 } ) ;
30273027 } ) ;
30283028 } ) ;
3029+
3030+ describe ( "event type with max bookings count per booker" , ( ) => {
3031+ it ( "should not allow booking more than maximumActiveBookings per attendee" , async ( ) => {
3032+ const eventTypeIdWithMaxBookerBookings = await eventTypesRepositoryFixture . create (
3033+ {
3034+ slug : `max-bookings-count-per-booker-${ randomString ( 10 ) } ` ,
3035+ length : 60 ,
3036+ title : "Event Type with max bookings count per booker" ,
3037+ maxActiveBookingsPerBooker : 1 ,
3038+ } ,
3039+ user . id
3040+ ) ;
3041+
3042+ const body : CreateBookingInput_2024_08_13 = {
3043+ start : new Date ( Date . UTC ( 2040 , 0 , 13 , 10 , 0 , 0 ) ) . toISOString ( ) ,
3044+ eventTypeId : eventTypeIdWithMaxBookerBookings . id ,
3045+ attendee : {
3046+ name : "alice" ,
3047+ email : "alice@gmail.com" ,
3048+ timeZone : "Europe/Rome" ,
3049+ language : "it" ,
3050+ } ,
3051+ } ;
3052+
3053+ const response = await request ( app . getHttpServer ( ) )
3054+ . post ( "/v2/bookings" )
3055+ . send ( body )
3056+ . set ( CAL_API_VERSION_HEADER , VERSION_2024_08_13 )
3057+ . expect ( 201 ) ;
3058+
3059+ const responseBody : CreateBookingOutput_2024_08_13 = response . body ;
3060+ expect ( responseBody . status ) . toEqual ( SUCCESS_STATUS ) ;
3061+ expect ( responseBody . data ) . toBeDefined ( ) ;
3062+ expect ( responseDataIsBooking ( responseBody . data ) ) . toBe ( true ) ;
3063+
3064+ if ( responseDataIsBooking ( responseBody . data ) ) {
3065+ const data : BookingOutput_2024_08_13 = responseBody . data ;
3066+ expect ( data . id ) . toBeDefined ( ) ;
3067+ } else {
3068+ throw new Error (
3069+ "Invalid response data - expected booking but received array of possibly recurring bookings"
3070+ ) ;
3071+ }
3072+
3073+ const response2 = await request ( app . getHttpServer ( ) )
3074+ . post ( "/v2/bookings" )
3075+ . send ( body )
3076+ . set ( CAL_API_VERSION_HEADER , VERSION_2024_08_13 )
3077+ . expect ( 400 ) ;
3078+
3079+ expect ( response2 . body . error . message ) . toBe (
3080+ "Attendee with this email can't book because the maximum number of active bookings has been reached."
3081+ ) ;
3082+
3083+ const body2 : CreateBookingInput_2024_08_13 = {
3084+ start : new Date ( Date . UTC ( 2040 , 0 , 13 , 12 , 0 , 0 ) ) . toISOString ( ) ,
3085+ eventTypeId : eventTypeIdWithMaxBookerBookings . id ,
3086+ attendee : {
3087+ name : "bob" ,
3088+ email : "bob@gmail.com" ,
3089+ timeZone : "Europe/Rome" ,
3090+ language : "it" ,
3091+ } ,
3092+ } ;
3093+
3094+ const response3 = await request ( app . getHttpServer ( ) )
3095+ . post ( "/v2/bookings" )
3096+ . send ( body2 )
3097+ . set ( CAL_API_VERSION_HEADER , VERSION_2024_08_13 )
3098+ . expect ( 201 ) ;
3099+
3100+ const responseBody2 : CreateBookingOutput_2024_08_13 = response3 . body ;
3101+ expect ( responseBody2 . status ) . toEqual ( SUCCESS_STATUS ) ;
3102+ expect ( responseBody2 . data ) . toBeDefined ( ) ;
3103+ expect ( responseDataIsBooking ( responseBody2 . data ) ) . toBe ( true ) ;
3104+
3105+ if ( responseDataIsBooking ( responseBody2 . data ) ) {
3106+ const data : BookingOutput_2024_08_13 = responseBody2 . data ;
3107+ expect ( data . id ) . toBeDefined ( ) ;
3108+ } else {
3109+ throw new Error (
3110+ "Invalid response data - expected booking but received array of possibly recurring bookings"
3111+ ) ;
3112+ }
3113+ } ) ;
3114+
3115+ it ( "should not allow booking more than maximumActiveBookings per attendee and offer rescheduling" , async ( ) => {
3116+ const eventTypeIdWithMaxBookerBookings = await eventTypesRepositoryFixture . create (
3117+ {
3118+ slug : `max-bookings-count-per-booker-with-reschedule-${ randomString ( 10 ) } ` ,
3119+ length : 60 ,
3120+ title : "Event Type with max bookings count per booker with reschedule" ,
3121+ maxActiveBookingsPerBooker : 1 ,
3122+ maxActiveBookingPerBookerOfferReschedule : true ,
3123+ } ,
3124+ user . id
3125+ ) ;
3126+
3127+ const body : CreateBookingInput_2024_08_13 = {
3128+ start : new Date ( Date . UTC ( 2040 , 0 , 13 , 14 , 0 , 0 ) ) . toISOString ( ) ,
3129+ eventTypeId : eventTypeIdWithMaxBookerBookings . id ,
3130+ attendee : {
3131+ name : "charlie" ,
3132+ email : "charlie@gmail.com" ,
3133+ timeZone : "Europe/Rome" ,
3134+ language : "it" ,
3135+ } ,
3136+ } ;
3137+
3138+ const response = await request ( app . getHttpServer ( ) )
3139+ . post ( "/v2/bookings" )
3140+ . send ( body )
3141+ . set ( CAL_API_VERSION_HEADER , VERSION_2024_08_13 )
3142+ . expect ( 201 ) ;
3143+
3144+ const responseBody : CreateBookingOutput_2024_08_13 = response . body ;
3145+ expect ( responseBody . status ) . toEqual ( SUCCESS_STATUS ) ;
3146+ expect ( responseBody . data ) . toBeDefined ( ) ;
3147+ expect ( responseDataIsBooking ( responseBody . data ) ) . toBe ( true ) ;
3148+
3149+ if ( responseDataIsBooking ( responseBody . data ) ) {
3150+ const data : BookingOutput_2024_08_13 = responseBody . data ;
3151+ expect ( data . id ) . toBeDefined ( ) ;
3152+ } else {
3153+ throw new Error (
3154+ "Invalid response data - expected booking but received array of possibly recurring bookings"
3155+ ) ;
3156+ }
3157+
3158+ const response2 = await request ( app . getHttpServer ( ) )
3159+ . post ( "/v2/bookings" )
3160+ . send ( body )
3161+ . set ( CAL_API_VERSION_HEADER , VERSION_2024_08_13 )
3162+ . expect ( 400 ) ;
3163+
3164+ expect ( response2 . body . error . message ) . toBe (
3165+ `Attendee with this email can't book because the maximum number of active bookings has been reached. You can reschedule your existing booking (${ responseBody . data . uid } ) to a new timeslot instead.`
3166+ ) ;
3167+ } ) ;
3168+ } ) ;
30293169 } ) ;
30303170 } ) ;
30313171
3032- function responseDataIsRecurranceBooking ( data : any ) : data is RecurringBookingOutput_2024_08_13 {
3172+ function responseDataIsRecurranceBooking ( data : unknown ) : data is RecurringBookingOutput_2024_08_13 {
30333173 return (
30343174 ! Array . isArray ( data ) &&
30353175 typeof data === "object" &&
3176+ data !== null &&
30363177 data &&
30373178 "id" in data &&
30383179 "recurringBookingUid" in data
@@ -3048,11 +3189,11 @@ describe("Bookings Endpoints 2024-08-13", () => {
30483189 } ) ;
30493190 } ) ;
30503191
3051- function responseDataIsBooking ( data : any ) : data is BookingOutput_2024_08_13 {
3052- return ! Array . isArray ( data ) && typeof data === "object" && data && "id" in data ;
3192+ function responseDataIsBooking ( data : unknown ) : data is BookingOutput_2024_08_13 {
3193+ return ! Array . isArray ( data ) && typeof data === "object" && data !== null && data && "id" in data ;
30533194 }
30543195
3055- function responseDataIsRecurringBooking ( data : any ) : data is RecurringBookingOutput_2024_08_13 [ ] {
3196+ function responseDataIsRecurringBooking ( data : unknown ) : data is RecurringBookingOutput_2024_08_13 [ ] {
30563197 return Array . isArray ( data ) ;
30573198 }
30583199} ) ;
0 commit comments