@venulog/phasing-engine-schemas 0.4.3 → 0.5.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/enums/index.d.ts +0 -1
- package/dist/enums/index.js +0 -1
- package/dist/index.d.ts +1 -3
- package/dist/index.js +1 -3
- package/dist/parkingArea.d.ts +69 -0
- package/dist/parkingArea.js +153 -0
- package/dist/parkingBooking.d.ts +798 -0
- package/dist/parkingBooking.js +734 -0
- package/package.json +75 -79
- package/dist/enums/phaseSlotScheduleType.d.ts +0 -4
- package/dist/enums/phaseSlotScheduleType.js +0 -5
- package/dist/phaseBooking.d.ts +0 -1346
- package/dist/phaseBooking.js +0 -1369
- package/dist/phaseSlot.d.ts +0 -139
- package/dist/phaseSlot.js +0 -276
package/dist/phaseBooking.js
DELETED
|
@@ -1,1369 +0,0 @@
|
|
|
1
|
-
// packages/phasing-schemas/src/phaseBooking.ts
|
|
2
|
-
import { paginationSchema } from './pagination.js';
|
|
3
|
-
import { BookingStatus } from './enums/bookingStatus.js';
|
|
4
|
-
import { createSuccessResponseSchema, createMessageDataResponseSchema, documentSchema } from './common.js';
|
|
5
|
-
import { z } from './zod.js';
|
|
6
|
-
import { PhaseSlotScheduleType } from './enums/phaseSlotScheduleType.js';
|
|
7
|
-
import { ParkingAreaScheduleType } from './enums/parkingAreaScheduleType.js';
|
|
8
|
-
// PostGIS geometry schema (GeoJSON-like structure)
|
|
9
|
-
export const geometrySchema = z
|
|
10
|
-
.object({
|
|
11
|
-
type: z.enum([
|
|
12
|
-
'Polygon',
|
|
13
|
-
'MultiPolygon',
|
|
14
|
-
'Point',
|
|
15
|
-
'LineString',
|
|
16
|
-
'MultiLineString',
|
|
17
|
-
'MultiPoint'
|
|
18
|
-
]),
|
|
19
|
-
coordinates: z.array(z.unknown()),
|
|
20
|
-
crs: z
|
|
21
|
-
.object({
|
|
22
|
-
type: z.literal('name'),
|
|
23
|
-
properties: z.object({
|
|
24
|
-
name: z.string()
|
|
25
|
-
})
|
|
26
|
-
})
|
|
27
|
-
.optional()
|
|
28
|
-
})
|
|
29
|
-
.nullable()
|
|
30
|
-
.openapi({
|
|
31
|
-
description: 'PostGIS geometry object (GeoJSON format)',
|
|
32
|
-
example: {
|
|
33
|
-
type: 'Polygon',
|
|
34
|
-
coordinates: [
|
|
35
|
-
[
|
|
36
|
-
[2.3522, 48.8566],
|
|
37
|
-
[2.3532, 48.8566],
|
|
38
|
-
[2.3532, 48.8576],
|
|
39
|
-
[2.3522, 48.8576],
|
|
40
|
-
[2.3522, 48.8566]
|
|
41
|
-
]
|
|
42
|
-
]
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
// ------------------------------
|
|
46
|
-
// Query parameters schema
|
|
47
|
-
// ------------------------------
|
|
48
|
-
export const getEventBookingsQuerySchema = z
|
|
49
|
-
.object({
|
|
50
|
-
event_code: z.string().min(1, 'Event code is required').openapi({
|
|
51
|
-
description: 'Unique code identifying the event',
|
|
52
|
-
example: 'COEC2025'
|
|
53
|
-
}),
|
|
54
|
-
seller_id: z
|
|
55
|
-
.string()
|
|
56
|
-
.min(1, 'Seller ID is required')
|
|
57
|
-
.transform(val => parseInt(val, 10))
|
|
58
|
-
.refine(val => !isNaN(val) && val > 0, { message: 'Seller ID must be positive' })
|
|
59
|
-
.openapi({
|
|
60
|
-
description: 'ID of the seller (must be a positive integer)',
|
|
61
|
-
example: '1'
|
|
62
|
-
})
|
|
63
|
-
})
|
|
64
|
-
.extend(paginationSchema.shape)
|
|
65
|
-
.openapi('GetEventBookingsQuery');
|
|
66
|
-
export const closeEventParamsSchema = z
|
|
67
|
-
.object({
|
|
68
|
-
eventId: z
|
|
69
|
-
.string()
|
|
70
|
-
.min(1, 'Event ID is required')
|
|
71
|
-
.transform(val => parseInt(val, 10))
|
|
72
|
-
.refine(val => !isNaN(val) && val > 0, { message: 'Event ID must be positive' })
|
|
73
|
-
.openapi({
|
|
74
|
-
description: 'The ID of the event to close',
|
|
75
|
-
example: '1'
|
|
76
|
-
})
|
|
77
|
-
})
|
|
78
|
-
.openapi('CloseEventParams');
|
|
79
|
-
export const closeEventBodySchema = z
|
|
80
|
-
.object({
|
|
81
|
-
reason: z.string().optional().openapi({
|
|
82
|
-
description: 'Optional reason for closing the event phase (for audit purposes)',
|
|
83
|
-
example: 'Event phase completed - moving to next stage'
|
|
84
|
-
})
|
|
85
|
-
})
|
|
86
|
-
.openapi('CloseEventBody');
|
|
87
|
-
// ------------------------------
|
|
88
|
-
// Response schemas
|
|
89
|
-
// ------------------------------
|
|
90
|
-
export const vehicleTypeSchema = z.object({
|
|
91
|
-
id: z.number(),
|
|
92
|
-
name: z.string()
|
|
93
|
-
});
|
|
94
|
-
// New unified phase slot schedule schema (from database response)
|
|
95
|
-
export const phaseSlotScheduleSchema = z
|
|
96
|
-
.object({
|
|
97
|
-
id: z.number().int().positive().openapi({
|
|
98
|
-
description: 'Unique identifier for the schedule',
|
|
99
|
-
example: 1
|
|
100
|
-
}),
|
|
101
|
-
date: z.string().openapi({
|
|
102
|
-
description: 'Date of the schedule (YYYY-MM-DD format)',
|
|
103
|
-
example: '2025-12-15'
|
|
104
|
-
}),
|
|
105
|
-
start_time: z.string().openapi({
|
|
106
|
-
description: 'Start time (HH:MM format)',
|
|
107
|
-
example: '06:00'
|
|
108
|
-
}),
|
|
109
|
-
end_time: z.string().openapi({
|
|
110
|
-
description: 'End time (HH:MM format)',
|
|
111
|
-
example: '09:00'
|
|
112
|
-
}),
|
|
113
|
-
duration: z.number().openapi({
|
|
114
|
-
description: 'Duration in minutes',
|
|
115
|
-
example: 180
|
|
116
|
-
}),
|
|
117
|
-
phase_slot_id: z.number().int().positive().openapi({
|
|
118
|
-
description: 'ID of the associated phase slot',
|
|
119
|
-
example: 101
|
|
120
|
-
}),
|
|
121
|
-
phase_slot_schedule_type: z
|
|
122
|
-
.enum([PhaseSlotScheduleType.ASSEMBLY, PhaseSlotScheduleType.DISMANTLING])
|
|
123
|
-
.openapi({
|
|
124
|
-
description: 'Type of schedule',
|
|
125
|
-
example: PhaseSlotScheduleType.ASSEMBLY
|
|
126
|
-
}),
|
|
127
|
-
created_at: z.string().openapi({
|
|
128
|
-
description: 'Timestamp when schedule was created',
|
|
129
|
-
example: '2025-12-09T10:00:00.000Z'
|
|
130
|
-
}),
|
|
131
|
-
updated_at: z.string().openapi({
|
|
132
|
-
description: 'Timestamp when schedule was updated',
|
|
133
|
-
example: '2025-12-09T10:30:00.000Z'
|
|
134
|
-
}),
|
|
135
|
-
created_by: z.uuid().nullable().openapi({
|
|
136
|
-
description: 'UUID of user who created the schedule',
|
|
137
|
-
example: '550e8400-e29b-41d4-a716-446655440000'
|
|
138
|
-
}),
|
|
139
|
-
updated_by: z.uuid().nullable().openapi({
|
|
140
|
-
description: 'UUID of user who last updated the schedule',
|
|
141
|
-
example: '550e8400-e29b-41d4-a716-446655440000'
|
|
142
|
-
})
|
|
143
|
-
})
|
|
144
|
-
.openapi('PhaseSlotSchedule');
|
|
145
|
-
export const companySchema = z.object({
|
|
146
|
-
id: z.number(),
|
|
147
|
-
company_name: z.string(),
|
|
148
|
-
vat_number: z.string().nullable(),
|
|
149
|
-
siret_code: z.string().nullable(),
|
|
150
|
-
tva_intracom: z.string().nullable(),
|
|
151
|
-
type: z.enum(['E', 'S']),
|
|
152
|
-
company_role: z.string().nullable(),
|
|
153
|
-
company_street: z.string().nullable(),
|
|
154
|
-
company_city: z.string().nullable(),
|
|
155
|
-
company_postal_code: z.string().nullable(),
|
|
156
|
-
company_country: z.string().nullable(),
|
|
157
|
-
company_address: z.string().nullable(),
|
|
158
|
-
contact_first_name: z.string().nullable(),
|
|
159
|
-
contact_last_name: z.string().nullable(),
|
|
160
|
-
contact_email: z.string().nullable(),
|
|
161
|
-
contact_phone: z.string().nullable(),
|
|
162
|
-
is_active: z.boolean(),
|
|
163
|
-
created_at: z.string(),
|
|
164
|
-
updated_at: z.string(),
|
|
165
|
-
created_by: z.string().nullable(),
|
|
166
|
-
updated_by: z.string().nullable()
|
|
167
|
-
});
|
|
168
|
-
export const phaseBookingSchema = z.object({
|
|
169
|
-
id: z.number(),
|
|
170
|
-
phase_slot_schedule_id: z.number(),
|
|
171
|
-
status: z.enum(BookingStatus),
|
|
172
|
-
is_active: z.boolean(),
|
|
173
|
-
created_at: z.string(),
|
|
174
|
-
updated_at: z.string(),
|
|
175
|
-
created_by: z.string().nullable(),
|
|
176
|
-
updated_by: z.string().nullable(),
|
|
177
|
-
booking_date: z.string().nullable(),
|
|
178
|
-
start_time: z.string().nullable(),
|
|
179
|
-
end_time: z.string().nullable(),
|
|
180
|
-
company_role: z.string().nullable(),
|
|
181
|
-
company: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
182
|
-
vehicle: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
183
|
-
// Include the schedule details
|
|
184
|
-
phase_slot_schedule: phaseSlotScheduleSchema.optional()
|
|
185
|
-
});
|
|
186
|
-
export const companyDetailsSchema = z
|
|
187
|
-
.object({
|
|
188
|
-
hall: z.string().min(1, 'Hall is required').openapi({
|
|
189
|
-
description: 'Hall location',
|
|
190
|
-
example: 'Hall 1'
|
|
191
|
-
}),
|
|
192
|
-
stand_number: z.string().min(1, 'Stand number is required').openapi({
|
|
193
|
-
description: 'Stand number',
|
|
194
|
-
example: 'A-123'
|
|
195
|
-
}),
|
|
196
|
-
company_name: z.string().min(1, 'Company name is required').openapi({
|
|
197
|
-
description: 'Company name',
|
|
198
|
-
example: 'Acme Corp'
|
|
199
|
-
}),
|
|
200
|
-
business: z.string().min(1, 'Business is required').openapi({
|
|
201
|
-
description: 'Type of business',
|
|
202
|
-
example: 'Technology'
|
|
203
|
-
}),
|
|
204
|
-
departure_city: z.string().min(1, 'Departure city is required').openapi({
|
|
205
|
-
description: 'City of departure',
|
|
206
|
-
example: 'Paris'
|
|
207
|
-
}),
|
|
208
|
-
contact_name: z.string().min(1, 'Contact name is required').openapi({
|
|
209
|
-
description: 'Contact person name',
|
|
210
|
-
example: 'John Doe'
|
|
211
|
-
}),
|
|
212
|
-
email: z.email('Valid email is required').openapi({
|
|
213
|
-
description: 'Contact email',
|
|
214
|
-
example: 'john.doe@acme.com'
|
|
215
|
-
}),
|
|
216
|
-
phone: z.string().min(1, 'Phone is required').openapi({
|
|
217
|
-
description: 'Contact phone number',
|
|
218
|
-
example: '+33 1 23 45 67 89'
|
|
219
|
-
}),
|
|
220
|
-
driver_name: z.string().min(1, 'Driver name is required').openapi({
|
|
221
|
-
description: 'Driver name',
|
|
222
|
-
example: 'Jean Martin'
|
|
223
|
-
}),
|
|
224
|
-
driver_phone: z.string().min(1, 'Driver phone is required').openapi({
|
|
225
|
-
description: 'Driver phone number',
|
|
226
|
-
example: '+33 6 12 34 56 78'
|
|
227
|
-
}),
|
|
228
|
-
transport_company: z.string().min(1, 'Transport company is required').openapi({
|
|
229
|
-
description: 'Transport company name',
|
|
230
|
-
example: 'Fast Transport Ltd'
|
|
231
|
-
})
|
|
232
|
-
})
|
|
233
|
-
.openapi('CompanyDetails');
|
|
234
|
-
export const vehicleDetailsSchema = z
|
|
235
|
-
.object({
|
|
236
|
-
vehicle_type: z.string().min(1, 'Vehicle type is required').openapi({
|
|
237
|
-
description: 'Type of vehicle',
|
|
238
|
-
example: 'Truck'
|
|
239
|
-
}),
|
|
240
|
-
unloading_method: z.string().min(1, 'Unloading method is required').openapi({
|
|
241
|
-
description: 'Method of unloading',
|
|
242
|
-
example: 'Manual'
|
|
243
|
-
}),
|
|
244
|
-
license_plate: z.string().min(1, 'License plate is required').openapi({
|
|
245
|
-
description: 'Vehicle license plate',
|
|
246
|
-
example: 'AB-123-CD'
|
|
247
|
-
}),
|
|
248
|
-
trailer_registration: z.string().optional().openapi({
|
|
249
|
-
description: 'Trailer registration number',
|
|
250
|
-
example: 'TR-456-EF'
|
|
251
|
-
})
|
|
252
|
-
})
|
|
253
|
-
.openapi('VehicleDetails');
|
|
254
|
-
export const createBookingBodySchema = z
|
|
255
|
-
.object({
|
|
256
|
-
// Event & Basic Info
|
|
257
|
-
event_id: z
|
|
258
|
-
.number()
|
|
259
|
-
.int()
|
|
260
|
-
.positive({
|
|
261
|
-
message: 'Event ID must be a positive integer'
|
|
262
|
-
})
|
|
263
|
-
.openapi({
|
|
264
|
-
description: 'ID of the event to create the booking for',
|
|
265
|
-
example: 1
|
|
266
|
-
}),
|
|
267
|
-
request_type: z
|
|
268
|
-
.enum([PhaseSlotScheduleType.ASSEMBLY, PhaseSlotScheduleType.DISMANTLING])
|
|
269
|
-
.default(PhaseSlotScheduleType.ASSEMBLY)
|
|
270
|
-
.openapi({
|
|
271
|
-
description: 'Type of request (assembly or dismantling)',
|
|
272
|
-
example: PhaseSlotScheduleType.ASSEMBLY
|
|
273
|
-
}),
|
|
274
|
-
// Time slot selection
|
|
275
|
-
selected_date: z.string().min(1, 'Date is required').openapi({
|
|
276
|
-
description: 'Selected date (YYYY-MM-DD)',
|
|
277
|
-
example: '2025-12-15'
|
|
278
|
-
}),
|
|
279
|
-
selected_time: z.string().min(1, 'Time is required').openapi({
|
|
280
|
-
description: 'Selected time slot (HH:MM)',
|
|
281
|
-
example: '08:00'
|
|
282
|
-
}),
|
|
283
|
-
// Company role for this booking
|
|
284
|
-
company_role: z.string().min(1, 'Company role is required').openapi({
|
|
285
|
-
description: 'Company role for this booking',
|
|
286
|
-
example: 'exhibitor'
|
|
287
|
-
}),
|
|
288
|
-
// Company details
|
|
289
|
-
company: companyDetailsSchema.openapi({
|
|
290
|
-
description: 'Company details including stand, contact, and driver info'
|
|
291
|
-
}),
|
|
292
|
-
// Vehicle details
|
|
293
|
-
vehicle: vehicleDetailsSchema.openapi({
|
|
294
|
-
description: 'Vehicle details'
|
|
295
|
-
})
|
|
296
|
-
})
|
|
297
|
-
.openapi('CreateBookingBody');
|
|
298
|
-
export const createBookingDataSchema = z
|
|
299
|
-
.object({
|
|
300
|
-
booking_id: z.number().openapi({
|
|
301
|
-
description: 'ID of the created booking',
|
|
302
|
-
example: 789
|
|
303
|
-
}),
|
|
304
|
-
phase_slot_schedule_id: z.number().openapi({
|
|
305
|
-
description: 'ID of the phase slot schedule',
|
|
306
|
-
example: 456
|
|
307
|
-
}),
|
|
308
|
-
status: z.enum(BookingStatus).openapi({
|
|
309
|
-
description: 'Booking status',
|
|
310
|
-
example: BookingStatus.BOOKED
|
|
311
|
-
}),
|
|
312
|
-
booking_date: z.string().openapi({
|
|
313
|
-
description: 'Booking date',
|
|
314
|
-
example: '2025-12-15'
|
|
315
|
-
}),
|
|
316
|
-
start_time: z.string().openapi({
|
|
317
|
-
description: 'Start time',
|
|
318
|
-
example: '08:00'
|
|
319
|
-
}),
|
|
320
|
-
end_time: z.string().openapi({
|
|
321
|
-
description: 'End time',
|
|
322
|
-
example: '08:30'
|
|
323
|
-
}),
|
|
324
|
-
company_role: z.string().nullable().openapi({
|
|
325
|
-
description: 'Company role for this booking',
|
|
326
|
-
example: 'exhibitor'
|
|
327
|
-
}),
|
|
328
|
-
company: companyDetailsSchema.openapi({
|
|
329
|
-
description: 'Company details including stand, contact, and driver info'
|
|
330
|
-
}),
|
|
331
|
-
vehicle: vehicleDetailsSchema.openapi({
|
|
332
|
-
description: 'Vehicle details'
|
|
333
|
-
}),
|
|
334
|
-
created_at: z.string().openapi({
|
|
335
|
-
description: 'Timestamp when booking was created',
|
|
336
|
-
example: '2025-12-05T10:30:00.000Z'
|
|
337
|
-
}),
|
|
338
|
-
created_by: z.string().nullable().openapi({
|
|
339
|
-
description: 'ID of the user who created the booking',
|
|
340
|
-
example: 'user-123'
|
|
341
|
-
})
|
|
342
|
-
})
|
|
343
|
-
.openapi('CreateBookingData');
|
|
344
|
-
export const createBookingResponseSchema = createMessageDataResponseSchema(createBookingDataSchema, 'CreateBookingResponse', 'Booking created successfully', 'Details of the created booking');
|
|
345
|
-
export const eventBookingsDataSchema = z
|
|
346
|
-
.object({
|
|
347
|
-
event_id: z.number(),
|
|
348
|
-
event_code: z.string(),
|
|
349
|
-
event_name: z.string(),
|
|
350
|
-
bookings: z.array(phaseBookingSchema),
|
|
351
|
-
total_count: z.number()
|
|
352
|
-
})
|
|
353
|
-
.openapi('EventBookingsData');
|
|
354
|
-
export const eventBookingsResponseSchema = createSuccessResponseSchema(eventBookingsDataSchema, 'EventBookingsResponse', 'Event bookings data with phase slot details');
|
|
355
|
-
export const closeEventDataSchema = z
|
|
356
|
-
.object({
|
|
357
|
-
event_id: z.number().openapi({
|
|
358
|
-
description: 'ID of the close event',
|
|
359
|
-
example: 1
|
|
360
|
-
}),
|
|
361
|
-
event_code: z.string().nullable().openapi({
|
|
362
|
-
description: 'Code of the close event',
|
|
363
|
-
example: 'EVENT2025'
|
|
364
|
-
}),
|
|
365
|
-
event_name: z.string().openapi({
|
|
366
|
-
description: 'Name of the close event',
|
|
367
|
-
example: 'Annual Trade Show 2025'
|
|
368
|
-
}),
|
|
369
|
-
is_active: z.boolean().openapi({
|
|
370
|
-
description: 'Active status of the event',
|
|
371
|
-
example: false
|
|
372
|
-
}),
|
|
373
|
-
close_at: z.string().openapi({
|
|
374
|
-
description: 'Timestamp when the event was closed',
|
|
375
|
-
example: '2025-12-04T10:30:00.000Z'
|
|
376
|
-
}),
|
|
377
|
-
close_by: z.string().nullable().openapi({
|
|
378
|
-
description: 'ID of the user who closed the event',
|
|
379
|
-
example: null
|
|
380
|
-
}),
|
|
381
|
-
reason: z.string().nullable().openapi({
|
|
382
|
-
description: 'Reason for closing the event',
|
|
383
|
-
example: 'Event cancelled due to logistical issues'
|
|
384
|
-
})
|
|
385
|
-
})
|
|
386
|
-
.openapi('CloseEventData');
|
|
387
|
-
export const closeEventResponseSchema = createMessageDataResponseSchema(closeEventDataSchema, 'CloseEventResponse', 'Event phase closed successfully', 'Details of the closed event phase');
|
|
388
|
-
export const confirmBookingParamsSchema = z.object({
|
|
389
|
-
bookingId: z.coerce.number().int().positive({
|
|
390
|
-
message: 'Booking ID must be a positive integer'
|
|
391
|
-
})
|
|
392
|
-
});
|
|
393
|
-
// Updated confirm booking response to include schedule_id instead of slot_id
|
|
394
|
-
export const confirmBookingResponseSchema = z.object({
|
|
395
|
-
success: z.boolean(),
|
|
396
|
-
message: z.string(),
|
|
397
|
-
data: z.object({
|
|
398
|
-
booking_id: z.number(),
|
|
399
|
-
booking_status: z.enum(BookingStatus),
|
|
400
|
-
schedule_id: z.number().openapi({
|
|
401
|
-
description: 'ID of the phase slot schedule',
|
|
402
|
-
example: 456
|
|
403
|
-
}),
|
|
404
|
-
confirmed_at: z.string(),
|
|
405
|
-
confirmed_by: z.string().nullable()
|
|
406
|
-
})
|
|
407
|
-
});
|
|
408
|
-
export const confirmAccessDataSchema = z.object({
|
|
409
|
-
bookingId: z.coerce.number().int().positive({
|
|
410
|
-
message: 'Booking ID must be a positive integer'
|
|
411
|
-
})
|
|
412
|
-
});
|
|
413
|
-
export const confirmAccessResponseSchema = z.object({
|
|
414
|
-
success: z.boolean(),
|
|
415
|
-
message: z.string(),
|
|
416
|
-
data: z.object({
|
|
417
|
-
booking_id: z.number(),
|
|
418
|
-
scanned_at: z.string()
|
|
419
|
-
})
|
|
420
|
-
});
|
|
421
|
-
export const refuseBookingParamsSchema = z
|
|
422
|
-
.object({
|
|
423
|
-
bookingId: z.coerce
|
|
424
|
-
.number()
|
|
425
|
-
.int()
|
|
426
|
-
.positive({
|
|
427
|
-
message: 'Booking ID must be a positive integer'
|
|
428
|
-
})
|
|
429
|
-
.openapi({
|
|
430
|
-
description: 'The ID of the booking to refuse',
|
|
431
|
-
example: 1
|
|
432
|
-
})
|
|
433
|
-
})
|
|
434
|
-
.openapi('RefuseBookingParams');
|
|
435
|
-
// Updated refuse booking response to include schedule_id instead of slot_id
|
|
436
|
-
export const refuseBookingDataSchema = z
|
|
437
|
-
.object({
|
|
438
|
-
booking_id: z.number().openapi({
|
|
439
|
-
description: 'ID of the refused booking',
|
|
440
|
-
example: 1
|
|
441
|
-
}),
|
|
442
|
-
booking_status: z.enum([BookingStatus.REFUSED]).openapi({
|
|
443
|
-
description: 'New status of the booking',
|
|
444
|
-
example: BookingStatus.REFUSED
|
|
445
|
-
}),
|
|
446
|
-
schedule_id: z.number().openapi({
|
|
447
|
-
description: 'ID of the associated phase slot schedule',
|
|
448
|
-
example: 456
|
|
449
|
-
}),
|
|
450
|
-
refused_at: z.string().openapi({
|
|
451
|
-
description: 'ISO 8601 timestamp when the booking was refused',
|
|
452
|
-
example: '2025-12-08T10:30:00.000Z'
|
|
453
|
-
}),
|
|
454
|
-
refused_by: z.string().nullable().openapi({
|
|
455
|
-
description: 'ID of the user who refused the booking',
|
|
456
|
-
example: 'user-123'
|
|
457
|
-
})
|
|
458
|
-
})
|
|
459
|
-
.openapi('RefuseBookingData');
|
|
460
|
-
export const refuseBookingResponseSchema = createMessageDataResponseSchema(refuseBookingDataSchema, 'RefuseBookingResponse', 'Phase booking refused successfully', 'Details of the refused booking');
|
|
461
|
-
// ------------------------------
|
|
462
|
-
// Create Phase Slots schemas
|
|
463
|
-
// ------------------------------
|
|
464
|
-
export const createPhaseSlotsBodySchema = z
|
|
465
|
-
.object({
|
|
466
|
-
event_id: z
|
|
467
|
-
.number()
|
|
468
|
-
.int()
|
|
469
|
-
.positive({
|
|
470
|
-
message: 'Event ID must be a positive integer'
|
|
471
|
-
})
|
|
472
|
-
.openapi({
|
|
473
|
-
description: 'ID of the event to create the slots for',
|
|
474
|
-
example: 1
|
|
475
|
-
}),
|
|
476
|
-
slots: z
|
|
477
|
-
.array(z.object({
|
|
478
|
-
name: z.string().min(1, 'Name is required and cannot be empty').openapi({
|
|
479
|
-
description: 'Name of the parking area (required)',
|
|
480
|
-
example: 'Zone A - Loading Dock'
|
|
481
|
-
}),
|
|
482
|
-
geometry: geometrySchema.optional().openapi({
|
|
483
|
-
description: 'PostGIS polygon geometry representing the parking area boundary (optional)',
|
|
484
|
-
example: {
|
|
485
|
-
type: 'Polygon',
|
|
486
|
-
coordinates: [
|
|
487
|
-
[
|
|
488
|
-
[2.3522, 48.8566],
|
|
489
|
-
[2.3532, 48.8566],
|
|
490
|
-
[2.3532, 48.8576],
|
|
491
|
-
[2.3522, 48.8576],
|
|
492
|
-
[2.3522, 48.8566]
|
|
493
|
-
]
|
|
494
|
-
]
|
|
495
|
-
}
|
|
496
|
-
}),
|
|
497
|
-
site_plan_image_url: z.url().nullable().optional().openapi({
|
|
498
|
-
description: 'URL to the site plan image (optional)',
|
|
499
|
-
example: 'https://storage.example.com/plans/zone-a.jpg'
|
|
500
|
-
}),
|
|
501
|
-
surface_area_sqm: z.number().positive().nullable().optional().openapi({
|
|
502
|
-
description: 'Surface area in square meters (optional, must be positive if provided)',
|
|
503
|
-
example: 150.5
|
|
504
|
-
})
|
|
505
|
-
}))
|
|
506
|
-
.min(1, 'At least one slot must be provided')
|
|
507
|
-
.openapi({
|
|
508
|
-
description: 'Array of slots to create with their properties',
|
|
509
|
-
example: [
|
|
510
|
-
{
|
|
511
|
-
name: 'Zone A - Loading Dock',
|
|
512
|
-
geometry: null,
|
|
513
|
-
site_plan_image_url: 'https://storage.example.com/plans/zone-a.jpg',
|
|
514
|
-
surface_area_sqm: 150.5
|
|
515
|
-
}
|
|
516
|
-
]
|
|
517
|
-
})
|
|
518
|
-
})
|
|
519
|
-
.openapi('CreatePhaseSlotsBody');
|
|
520
|
-
export const createPhaseSlotDataSchema = z
|
|
521
|
-
.object({
|
|
522
|
-
slot_id: z.number().openapi({
|
|
523
|
-
description: 'ID of the created phase slot',
|
|
524
|
-
example: 123
|
|
525
|
-
}),
|
|
526
|
-
event_id: z.number().openapi({
|
|
527
|
-
description: 'ID of the event',
|
|
528
|
-
example: 1
|
|
529
|
-
}),
|
|
530
|
-
name: z.string().openapi({
|
|
531
|
-
description: 'Name of the parking area',
|
|
532
|
-
example: 'Zone A - Loading Dock'
|
|
533
|
-
}),
|
|
534
|
-
geometry: geometrySchema.openapi({
|
|
535
|
-
description: 'PostGIS polygon geometry representing the parking area boundary',
|
|
536
|
-
example: {
|
|
537
|
-
type: 'Polygon',
|
|
538
|
-
coordinates: [
|
|
539
|
-
[
|
|
540
|
-
[2.3522, 48.8566],
|
|
541
|
-
[2.3532, 48.8566],
|
|
542
|
-
[2.3532, 48.8576],
|
|
543
|
-
[2.3522, 48.8576],
|
|
544
|
-
[2.3522, 48.8566]
|
|
545
|
-
]
|
|
546
|
-
]
|
|
547
|
-
}
|
|
548
|
-
}),
|
|
549
|
-
site_plan_image_url: z.string().nullable().openapi({
|
|
550
|
-
description: 'URL to the site plan image',
|
|
551
|
-
example: 'https://storage.example.com/plans/zone-a.jpg'
|
|
552
|
-
}),
|
|
553
|
-
surface_area_sqm: z.number().nullable().openapi({
|
|
554
|
-
description: 'Surface area in square meters',
|
|
555
|
-
example: 150.5
|
|
556
|
-
}),
|
|
557
|
-
is_active: z.boolean().openapi({
|
|
558
|
-
description: 'Whether the slot is active',
|
|
559
|
-
example: true,
|
|
560
|
-
examples: [true, false]
|
|
561
|
-
}),
|
|
562
|
-
created_at: z.string().openapi({
|
|
563
|
-
description: 'Timestamp when slot was created',
|
|
564
|
-
example: '2025-12-09T10:30:00.000Z'
|
|
565
|
-
}),
|
|
566
|
-
created_by: z.string().nullable().openapi({
|
|
567
|
-
description: 'ID of the user who created the slot',
|
|
568
|
-
example: 'user-123'
|
|
569
|
-
})
|
|
570
|
-
})
|
|
571
|
-
.openapi('CreatePhaseSlotData');
|
|
572
|
-
export const createPhaseSlotsDataSchema = z
|
|
573
|
-
.object({
|
|
574
|
-
event_id: z.number().openapi({
|
|
575
|
-
description: 'ID of the event',
|
|
576
|
-
example: 1
|
|
577
|
-
}),
|
|
578
|
-
total_created: z.number().openapi({
|
|
579
|
-
description: 'Total number of slots successfully created',
|
|
580
|
-
example: 2
|
|
581
|
-
}),
|
|
582
|
-
created_slots: z.array(createPhaseSlotDataSchema).openapi({
|
|
583
|
-
description: 'Array of successfully created slots',
|
|
584
|
-
example: []
|
|
585
|
-
}),
|
|
586
|
-
failed_slots: z
|
|
587
|
-
.array(z.object({
|
|
588
|
-
index: z.number().openapi({
|
|
589
|
-
description: 'Index of the slot in the request that failed to create',
|
|
590
|
-
example: 0
|
|
591
|
-
}),
|
|
592
|
-
error: z.string().openapi({
|
|
593
|
-
description: 'Error message explaining why the slot creation failed',
|
|
594
|
-
example: 'Failed to create slot'
|
|
595
|
-
})
|
|
596
|
-
}))
|
|
597
|
-
.openapi({
|
|
598
|
-
description: 'Array of slots that failed to create with error details',
|
|
599
|
-
example: []
|
|
600
|
-
})
|
|
601
|
-
})
|
|
602
|
-
.openapi('CreatePhaseSlotsData');
|
|
603
|
-
export const createPhaseSlotsResponseSchema = createMessageDataResponseSchema(createPhaseSlotsDataSchema, 'CreatePhaseSlotsResponse', 'Bulk phase slots operation completed', 'Details of the bulk creation operation including successes and failures');
|
|
604
|
-
// ------------------------------
|
|
605
|
-
// Update Phase Slot schemas
|
|
606
|
-
// ------------------------------
|
|
607
|
-
export const updatePhaseSlotParamsSchema = z
|
|
608
|
-
.object({
|
|
609
|
-
slotId: z
|
|
610
|
-
.string()
|
|
611
|
-
.min(1, 'Slot ID is required')
|
|
612
|
-
.transform(val => parseInt(val, 10))
|
|
613
|
-
.refine(val => !isNaN(val) && val > 0, { message: 'Slot ID must be positive' })
|
|
614
|
-
.openapi({
|
|
615
|
-
description: 'The ID of the phase slot to update',
|
|
616
|
-
example: '123'
|
|
617
|
-
})
|
|
618
|
-
})
|
|
619
|
-
.openapi('UpdatePhaseSlotParams');
|
|
620
|
-
export const updatePhaseSlotBodySchema = z
|
|
621
|
-
.object({
|
|
622
|
-
name: z.string().min(1, 'Name cannot be empty').optional().openapi({
|
|
623
|
-
description: 'New name for the parking area',
|
|
624
|
-
example: 'Zone B - Assembly Area'
|
|
625
|
-
}),
|
|
626
|
-
geometry: geometrySchema.optional().openapi({
|
|
627
|
-
description: 'New PostGIS polygon geometry',
|
|
628
|
-
example: {
|
|
629
|
-
type: 'Polygon',
|
|
630
|
-
coordinates: [
|
|
631
|
-
[
|
|
632
|
-
[2.3522, 48.8566],
|
|
633
|
-
[2.3532, 48.8566],
|
|
634
|
-
[2.3532, 48.8576],
|
|
635
|
-
[2.3522, 48.8576],
|
|
636
|
-
[2.3522, 48.8566]
|
|
637
|
-
]
|
|
638
|
-
]
|
|
639
|
-
}
|
|
640
|
-
}),
|
|
641
|
-
site_plan_image_url: z.string().url().nullable().optional().openapi({
|
|
642
|
-
description: 'New site plan image URL',
|
|
643
|
-
example: 'https://storage.example.com/plans/zone-b.jpg'
|
|
644
|
-
}),
|
|
645
|
-
surface_area_sqm: z.number().positive().nullable().optional().openapi({
|
|
646
|
-
description: 'New surface area in square meters (must be positive if provided)',
|
|
647
|
-
example: 200.0
|
|
648
|
-
})
|
|
649
|
-
})
|
|
650
|
-
.refine(data => Object.keys(data).length > 0, {
|
|
651
|
-
message: 'At least one field must be provided for update'
|
|
652
|
-
})
|
|
653
|
-
.openapi('UpdatePhaseSlotBody');
|
|
654
|
-
export const updatePhaseSlotDataSchema = z
|
|
655
|
-
.object({
|
|
656
|
-
slot_id: z.number().openapi({
|
|
657
|
-
description: 'ID of the updated phase slot',
|
|
658
|
-
example: 123
|
|
659
|
-
}),
|
|
660
|
-
event_id: z.number().openapi({
|
|
661
|
-
description: 'ID of the event',
|
|
662
|
-
example: 1
|
|
663
|
-
}),
|
|
664
|
-
name: z.string().openapi({
|
|
665
|
-
description: 'Name of the parking area',
|
|
666
|
-
example: 'Zone B - Assembly Area'
|
|
667
|
-
}),
|
|
668
|
-
geometry: geometrySchema.openapi({
|
|
669
|
-
description: 'PostGIS polygon geometry representing the parking area boundary',
|
|
670
|
-
example: {
|
|
671
|
-
type: 'Polygon',
|
|
672
|
-
coordinates: [
|
|
673
|
-
[
|
|
674
|
-
[2.3522, 48.8566],
|
|
675
|
-
[2.3532, 48.8566],
|
|
676
|
-
[2.3532, 48.8576],
|
|
677
|
-
[2.3522, 48.8576],
|
|
678
|
-
[2.3522, 48.8566]
|
|
679
|
-
]
|
|
680
|
-
]
|
|
681
|
-
}
|
|
682
|
-
}),
|
|
683
|
-
site_plan_image_url: z.string().nullable().openapi({
|
|
684
|
-
description: 'URL to the site plan image',
|
|
685
|
-
example: 'https://storage.example.com/plans/zone-b.jpg'
|
|
686
|
-
}),
|
|
687
|
-
surface_area_sqm: z.number().nullable().openapi({
|
|
688
|
-
description: 'Surface area in square meters',
|
|
689
|
-
example: 200.0
|
|
690
|
-
}),
|
|
691
|
-
is_active: z.boolean().openapi({
|
|
692
|
-
description: 'Whether the slot is active',
|
|
693
|
-
example: true
|
|
694
|
-
}),
|
|
695
|
-
updated_at: z.string().openapi({
|
|
696
|
-
description: 'Timestamp when slot was updated',
|
|
697
|
-
example: '2025-12-09T10:35:00.000Z'
|
|
698
|
-
}),
|
|
699
|
-
updated_by: z.string().nullable().openapi({
|
|
700
|
-
description: 'ID of the user who updated the slot',
|
|
701
|
-
example: 'user-123'
|
|
702
|
-
})
|
|
703
|
-
})
|
|
704
|
-
.openapi('UpdatePhaseSlotData');
|
|
705
|
-
export const updatePhaseSlotResponseSchema = createMessageDataResponseSchema(updatePhaseSlotDataSchema, 'UpdatePhaseSlotResponse', 'Phase slot updated successfully', 'Details of the updated phase slot');
|
|
706
|
-
// ------------------------------
|
|
707
|
-
// Phase Slot Schedules Schemas
|
|
708
|
-
// ------------------------------
|
|
709
|
-
export const upsertPhaseSlotScheduleItemSchema = z
|
|
710
|
-
.object({
|
|
711
|
-
id: z.number().int().positive().optional().openapi({
|
|
712
|
-
description: 'Unique identifier for existing schedule (required for updates)',
|
|
713
|
-
example: 1
|
|
714
|
-
}),
|
|
715
|
-
phase_slot_id: z.number().int().positive().openapi({
|
|
716
|
-
description: 'ID of the associated phase slot',
|
|
717
|
-
example: 101
|
|
718
|
-
}),
|
|
719
|
-
date: z
|
|
720
|
-
.string()
|
|
721
|
-
.regex(/^\d{4}-\d{2}-\d{2}$/, 'Date must be in YYYY-MM-DD format')
|
|
722
|
-
.openapi({
|
|
723
|
-
description: 'Date of the schedule (YYYY-MM-DD format)',
|
|
724
|
-
example: '2025-12-15'
|
|
725
|
-
}),
|
|
726
|
-
start_time: z
|
|
727
|
-
.string()
|
|
728
|
-
.regex(/^\d{2}:\d{2}$/, 'Time must be in HH:MM format')
|
|
729
|
-
.default('06:00')
|
|
730
|
-
.openapi({
|
|
731
|
-
description: 'Start time (HH:MM format)',
|
|
732
|
-
example: '06:00'
|
|
733
|
-
}),
|
|
734
|
-
end_time: z
|
|
735
|
-
.string()
|
|
736
|
-
.regex(/^\d{2}:\d{2}$/, 'Time must be in HH:MM format')
|
|
737
|
-
.default('09:00')
|
|
738
|
-
.openapi({
|
|
739
|
-
description: 'End time (HH:MM format)',
|
|
740
|
-
example: '09:00'
|
|
741
|
-
}),
|
|
742
|
-
duration: z.number().positive().default(60).openapi({
|
|
743
|
-
description: 'Duration in minutes',
|
|
744
|
-
example: 180
|
|
745
|
-
}),
|
|
746
|
-
phase_slot_schedule_type: z
|
|
747
|
-
.enum([PhaseSlotScheduleType.ASSEMBLY, PhaseSlotScheduleType.DISMANTLING])
|
|
748
|
-
.openapi({
|
|
749
|
-
description: 'Type of schedule',
|
|
750
|
-
example: PhaseSlotScheduleType.ASSEMBLY
|
|
751
|
-
}),
|
|
752
|
-
company_roles: z
|
|
753
|
-
.array(z.string())
|
|
754
|
-
.nullable()
|
|
755
|
-
.optional()
|
|
756
|
-
.openapi({
|
|
757
|
-
description: 'Array of company roles allowed for this schedule (moved from phase_slots)',
|
|
758
|
-
example: ['exhibitor', 'organizer', 'contractor']
|
|
759
|
-
})
|
|
760
|
-
})
|
|
761
|
-
.openapi('UpsertPhaseSlotScheduleItem');
|
|
762
|
-
export const deletePhaseSlotScheduleItemSchema = z
|
|
763
|
-
.object({
|
|
764
|
-
id: z.number().int().positive().openapi({
|
|
765
|
-
description: 'ID of the schedule to delete',
|
|
766
|
-
example: 1
|
|
767
|
-
})
|
|
768
|
-
})
|
|
769
|
-
.openapi('DeletePhaseSlotScheduleItem');
|
|
770
|
-
export const upsertPhaseSlotSchedulesBodySchema = z
|
|
771
|
-
.object({
|
|
772
|
-
upsert: z
|
|
773
|
-
.array(upsertPhaseSlotScheduleItemSchema)
|
|
774
|
-
.optional()
|
|
775
|
-
.openapi({
|
|
776
|
-
description: 'Array of schedules to create or update',
|
|
777
|
-
example: [
|
|
778
|
-
{
|
|
779
|
-
phase_slot_id: 101,
|
|
780
|
-
date: '2025-12-15',
|
|
781
|
-
start_time: '06:00',
|
|
782
|
-
end_time: '09:00',
|
|
783
|
-
duration: 180,
|
|
784
|
-
phase_slot_schedule_type: 'assembly'
|
|
785
|
-
},
|
|
786
|
-
{
|
|
787
|
-
id: 5,
|
|
788
|
-
phase_slot_id: 101,
|
|
789
|
-
date: '2025-12-16',
|
|
790
|
-
start_time: '15:00',
|
|
791
|
-
end_time: '18:00',
|
|
792
|
-
duration: 180,
|
|
793
|
-
phase_slot_schedule_type: 'dismantling'
|
|
794
|
-
}
|
|
795
|
-
]
|
|
796
|
-
}),
|
|
797
|
-
delete: z
|
|
798
|
-
.array(deletePhaseSlotScheduleItemSchema)
|
|
799
|
-
.optional()
|
|
800
|
-
.openapi({
|
|
801
|
-
description: 'Array of schedule IDs to delete',
|
|
802
|
-
example: [{ id: 42 }]
|
|
803
|
-
})
|
|
804
|
-
})
|
|
805
|
-
.refine(data => (data.upsert && data.upsert.length > 0) || (data.delete && data.delete.length > 0), {
|
|
806
|
-
message: 'At least one upsert or delete operation is required'
|
|
807
|
-
})
|
|
808
|
-
.openapi('UpsertPhaseSlotSchedulesBody');
|
|
809
|
-
export const upsertPhaseSlotSchedulesDataSchema = z
|
|
810
|
-
.object({
|
|
811
|
-
total_upserted: z.number().int().nonnegative().openapi({
|
|
812
|
-
description: 'Total number of schedules successfully upserted',
|
|
813
|
-
example: 3
|
|
814
|
-
}),
|
|
815
|
-
total_deleted: z.number().int().nonnegative().openapi({
|
|
816
|
-
description: 'Total number of schedules successfully deleted',
|
|
817
|
-
example: 1
|
|
818
|
-
}),
|
|
819
|
-
upserted_schedules: z.array(phaseSlotScheduleSchema).openapi({
|
|
820
|
-
description: 'Array of successfully upserted schedules'
|
|
821
|
-
}),
|
|
822
|
-
deleted_schedules: z
|
|
823
|
-
.array(z.object({
|
|
824
|
-
id: z.number().int().positive()
|
|
825
|
-
}))
|
|
826
|
-
.openapi({
|
|
827
|
-
description: 'Array of successfully deleted schedule IDs',
|
|
828
|
-
example: [{ id: 42 }]
|
|
829
|
-
}),
|
|
830
|
-
failed_operations: z
|
|
831
|
-
.array(z.object({
|
|
832
|
-
operation: z.enum(['upsert', 'delete']),
|
|
833
|
-
error: z.string(),
|
|
834
|
-
data: z.union([upsertPhaseSlotScheduleItemSchema, deletePhaseSlotScheduleItemSchema])
|
|
835
|
-
}))
|
|
836
|
-
.openapi({
|
|
837
|
-
description: 'Array of operations that failed to process',
|
|
838
|
-
example: [
|
|
839
|
-
{
|
|
840
|
-
operation: 'upsert',
|
|
841
|
-
error: 'Phase slot 999 not found or inactive',
|
|
842
|
-
data: {
|
|
843
|
-
phase_slot_id: 999,
|
|
844
|
-
date: '2025-12-15',
|
|
845
|
-
start_time: '06:00',
|
|
846
|
-
end_time: '09:00',
|
|
847
|
-
duration: 180,
|
|
848
|
-
phase_slot_schedule_type: 'assembly'
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
]
|
|
852
|
-
})
|
|
853
|
-
})
|
|
854
|
-
.openapi('UpsertPhaseSlotSchedulesData');
|
|
855
|
-
export const upsertPhaseSlotSchedulesResponseSchema = createMessageDataResponseSchema(upsertPhaseSlotSchedulesDataSchema, 'UpsertPhaseSlotSchedulesResponse', 'Phase slot schedules operation completed', 'Results of the upsert/delete operations');
|
|
856
|
-
// ------------------------------
|
|
857
|
-
// Check Slot Availability schemas
|
|
858
|
-
// ------------------------------
|
|
859
|
-
export const checkSlotAvailabilityBodySchema = z
|
|
860
|
-
.object({
|
|
861
|
-
schedule_id: z.number().positive().openapi({
|
|
862
|
-
description: 'The ID of the phase slot schedule',
|
|
863
|
-
example: 1
|
|
864
|
-
}),
|
|
865
|
-
date: z
|
|
866
|
-
.string()
|
|
867
|
-
.regex(/^\d{4}-\d{2}-\d{2}$/, 'Date must be in YYYY-MM-DD format')
|
|
868
|
-
.openapi({
|
|
869
|
-
description: 'The date to check availability (YYYY-MM-DD)',
|
|
870
|
-
example: '2025-12-15'
|
|
871
|
-
}),
|
|
872
|
-
start_time: z
|
|
873
|
-
.string()
|
|
874
|
-
.regex(/^\d{2}:\d{2}$/, 'Time must be in HH:MM format')
|
|
875
|
-
.openapi({
|
|
876
|
-
description: 'The start time to check availability (HH:MM)',
|
|
877
|
-
example: '08:00'
|
|
878
|
-
}),
|
|
879
|
-
company_role: z.string().min(1, 'Company role is required').openapi({
|
|
880
|
-
description: 'Company role to check availability for',
|
|
881
|
-
example: 'exhibitor'
|
|
882
|
-
})
|
|
883
|
-
})
|
|
884
|
-
.openapi('CheckSlotAvailabilityBody');
|
|
885
|
-
export const checkSlotAvailabilityDataSchema = z
|
|
886
|
-
.object({
|
|
887
|
-
schedule_id: z.number().openapi({
|
|
888
|
-
description: 'ID of the phase slot schedule',
|
|
889
|
-
example: 1
|
|
890
|
-
}),
|
|
891
|
-
date: z.string().openapi({
|
|
892
|
-
description: 'Date checked',
|
|
893
|
-
example: '2025-12-15'
|
|
894
|
-
}),
|
|
895
|
-
start_time: z.string().openapi({
|
|
896
|
-
description: 'Time slot checked',
|
|
897
|
-
example: '08:00'
|
|
898
|
-
}),
|
|
899
|
-
is_available: z.boolean().openapi({
|
|
900
|
-
description: 'Whether the slot is available for booking',
|
|
901
|
-
example: true
|
|
902
|
-
}),
|
|
903
|
-
max_capacity: z.number().openapi({
|
|
904
|
-
description: 'Maximum booking capacity',
|
|
905
|
-
example: 5
|
|
906
|
-
}),
|
|
907
|
-
current_bookings: z.number().openapi({
|
|
908
|
-
description: 'Current number of total bookings',
|
|
909
|
-
example: 3
|
|
910
|
-
}),
|
|
911
|
-
confirmed_bookings: z.number().openapi({
|
|
912
|
-
description: 'Current number of confirmed bookings',
|
|
913
|
-
example: 1
|
|
914
|
-
}),
|
|
915
|
-
available_capacity: z.number().openapi({
|
|
916
|
-
description: 'Remaining available capacity',
|
|
917
|
-
example: 2
|
|
918
|
-
})
|
|
919
|
-
})
|
|
920
|
-
.openapi('CheckSlotAvailabilityData');
|
|
921
|
-
export const checkSlotAvailabilityResponseSchema = createSuccessResponseSchema(checkSlotAvailabilityDataSchema, 'CheckSlotAvailabilityResponse', 'Slot availability information with capacity details');
|
|
922
|
-
// ------------------------------
|
|
923
|
-
// QR Code Generation schemas
|
|
924
|
-
// ------------------------------
|
|
925
|
-
export const getBookingDetailsParamsSchema = z
|
|
926
|
-
.object({
|
|
927
|
-
bookingId: z.coerce.number().int().positive({
|
|
928
|
-
message: 'Booking ID must be a positive integer'
|
|
929
|
-
})
|
|
930
|
-
})
|
|
931
|
-
.openapi('GetBookingDetailsParams');
|
|
932
|
-
export const bookingDetailsDataSchema = z
|
|
933
|
-
.object({
|
|
934
|
-
qr_token: z.string().nullable().openapi({
|
|
935
|
-
description: 'QR token for verification',
|
|
936
|
-
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
|
|
937
|
-
}),
|
|
938
|
-
id: z.number().openapi({
|
|
939
|
-
description: 'ID of the booking',
|
|
940
|
-
example: 123
|
|
941
|
-
}),
|
|
942
|
-
booking_id: z.number().openapi({
|
|
943
|
-
description: 'ID of the booking',
|
|
944
|
-
example: 123
|
|
945
|
-
}),
|
|
946
|
-
status: z.string().openapi({
|
|
947
|
-
description: 'Booking status',
|
|
948
|
-
example: 'confirmed'
|
|
949
|
-
}),
|
|
950
|
-
booking_date: z.string().openapi({
|
|
951
|
-
description: 'Date of the booking',
|
|
952
|
-
example: '2025-12-15'
|
|
953
|
-
}),
|
|
954
|
-
start_time: z.string().openapi({
|
|
955
|
-
description: 'Start time of the booking',
|
|
956
|
-
example: '08:00'
|
|
957
|
-
}),
|
|
958
|
-
end_time: z.string().openapi({
|
|
959
|
-
description: 'End time of the booking',
|
|
960
|
-
example: '08:30'
|
|
961
|
-
}),
|
|
962
|
-
company_role: z.string().nullable().openapi({
|
|
963
|
-
description: 'Company role for the booking',
|
|
964
|
-
example: 'exhibitor'
|
|
965
|
-
}),
|
|
966
|
-
company: companyDetailsSchema.openapi({
|
|
967
|
-
description: 'Company details'
|
|
968
|
-
}),
|
|
969
|
-
vehicle: vehicleDetailsSchema.openapi({
|
|
970
|
-
description: 'Vehicle details'
|
|
971
|
-
}),
|
|
972
|
-
event_id: z.number().openapi({
|
|
973
|
-
description: 'ID of the event',
|
|
974
|
-
example: 1
|
|
975
|
-
}),
|
|
976
|
-
event_name: z.string().openapi({
|
|
977
|
-
description: 'Name of the event',
|
|
978
|
-
example: 'Paris Fashion Week 2025'
|
|
979
|
-
}),
|
|
980
|
-
event_code: z.string().openapi({
|
|
981
|
-
description: 'Code of the event',
|
|
982
|
-
example: 'PFW2025'
|
|
983
|
-
}),
|
|
984
|
-
venue_id: z.number().nullable().openapi({
|
|
985
|
-
description: 'ID of the venue',
|
|
986
|
-
example: 1
|
|
987
|
-
}),
|
|
988
|
-
venue_name: z.string().nullable().openapi({
|
|
989
|
-
description: 'Name of the venue',
|
|
990
|
-
example: 'Paris Expo Porte de Versailles'
|
|
991
|
-
}),
|
|
992
|
-
request_type: z.string().openapi({
|
|
993
|
-
description: 'Type of phase slot schedule (assembly/dismantling)',
|
|
994
|
-
example: 'assembly'
|
|
995
|
-
}),
|
|
996
|
-
duration: z.number().openapi({
|
|
997
|
-
description: 'Duration of the booking in minutes',
|
|
998
|
-
example: 30
|
|
999
|
-
}),
|
|
1000
|
-
phase_slot_schedule_id: z.number().openapi({
|
|
1001
|
-
description: 'ID of the phase slot schedule',
|
|
1002
|
-
example: 456
|
|
1003
|
-
}),
|
|
1004
|
-
banner: documentSchema.nullable().openapi({
|
|
1005
|
-
description: 'Event banner document',
|
|
1006
|
-
example: {
|
|
1007
|
-
url: 'https://example.com/event-banner.jpg',
|
|
1008
|
-
name: 'event-banner.jpg',
|
|
1009
|
-
type: 'image/jpeg'
|
|
1010
|
-
}
|
|
1011
|
-
}),
|
|
1012
|
-
created_at: z.string().openapi({
|
|
1013
|
-
description: 'Timestamp when booking was created',
|
|
1014
|
-
example: '2025-12-05T10:30:00.000Z'
|
|
1015
|
-
}),
|
|
1016
|
-
updated_at: z.string().openapi({
|
|
1017
|
-
description: 'Timestamp when booking was last updated',
|
|
1018
|
-
example: '2025-12-05T10:30:00.000Z'
|
|
1019
|
-
})
|
|
1020
|
-
})
|
|
1021
|
-
.openapi('BookingDetailsData');
|
|
1022
|
-
export const getBookingDetailsResponseSchema = createSuccessResponseSchema(bookingDetailsDataSchema, 'GetBookingDetailsResponse', 'Booking details with access pass information');
|
|
1023
|
-
// ------------------------------
|
|
1024
|
-
// Get booking details by token schemas
|
|
1025
|
-
// ------------------------------
|
|
1026
|
-
export const getBookingDetailsByTokenBodySchema = z
|
|
1027
|
-
.object({
|
|
1028
|
-
access_token: z.string().min(1, 'Access token is required').openapi({
|
|
1029
|
-
description: 'Access pass token from confirmed booking',
|
|
1030
|
-
example: 'ACCESS_1a2b3c4d5e6f7g8h_eyJib29raW5nSWQiOjEyM30%3D'
|
|
1031
|
-
})
|
|
1032
|
-
})
|
|
1033
|
-
.openapi('GetBookingDetailsByTokenBody');
|
|
1034
|
-
export const getBookingDetailsByTokenResponseSchema = createSuccessResponseSchema(bookingDetailsDataSchema, 'GetBookingDetailsByTokenResponse', 'Booking details retrieved by access token');
|
|
1035
|
-
// ------------------------------
|
|
1036
|
-
// Get booking details by QR schemas
|
|
1037
|
-
// ------------------------------
|
|
1038
|
-
export const getBookingDetailsByQrBodySchema = z
|
|
1039
|
-
.object({
|
|
1040
|
-
qr_token: z.string().min(1, 'QR token is required').openapi({
|
|
1041
|
-
description: 'QR token from confirmed booking',
|
|
1042
|
-
example: 'ACCESS_1a2b3c4d5e6f7g8h_eyJib29raW5nSWQiOjEyM30%3D'
|
|
1043
|
-
})
|
|
1044
|
-
})
|
|
1045
|
-
.openapi('GetBookingDetailsByQrBody');
|
|
1046
|
-
export const getBookingDetailsByQrResponseSchema = createSuccessResponseSchema(bookingDetailsDataSchema, 'GetBookingDetailsByQrResponse', 'Booking details retrieved by QR token');
|
|
1047
|
-
// ------------------------------
|
|
1048
|
-
// Update Phase Booking schemas
|
|
1049
|
-
// ------------------------------
|
|
1050
|
-
export const updatePhaseBookingBodySchema = z
|
|
1051
|
-
.object({
|
|
1052
|
-
company: companyDetailsSchema.optional().openapi({
|
|
1053
|
-
description: 'Updated company details'
|
|
1054
|
-
}),
|
|
1055
|
-
vehicle: vehicleDetailsSchema.optional().openapi({
|
|
1056
|
-
description: 'Updated vehicle details'
|
|
1057
|
-
}),
|
|
1058
|
-
access_token: z.string().min(1, 'Access token is required').openapi({
|
|
1059
|
-
description: 'Access pass token for booking verification',
|
|
1060
|
-
example: 'ACCESS_1a2b3c4d5e6f7g8h_eyJib29raW5nSWQiOjF9'
|
|
1061
|
-
})
|
|
1062
|
-
})
|
|
1063
|
-
.refine(data => data.company !== undefined || data.vehicle !== undefined, {
|
|
1064
|
-
message: 'At least one field (company or vehicle) must be provided for update'
|
|
1065
|
-
})
|
|
1066
|
-
.openapi('UpdatePhaseBookingBody');
|
|
1067
|
-
export const updatePhaseBookingDataSchema = z
|
|
1068
|
-
.object({
|
|
1069
|
-
booking_id: z.number().openapi({
|
|
1070
|
-
description: 'ID of the updated booking',
|
|
1071
|
-
example: 1
|
|
1072
|
-
}),
|
|
1073
|
-
qr_token: z.string().openapi({
|
|
1074
|
-
description: 'New regenerated QR token',
|
|
1075
|
-
example: 'ACCESS_1a2b3c4d5e6f7g8h_eyJib29raW5nSWQiOjF9'
|
|
1076
|
-
}),
|
|
1077
|
-
company: companyDetailsSchema.nullable().openapi({
|
|
1078
|
-
description: 'Updated company details'
|
|
1079
|
-
}),
|
|
1080
|
-
vehicle: vehicleDetailsSchema.nullable().openapi({
|
|
1081
|
-
description: 'Updated vehicle details'
|
|
1082
|
-
}),
|
|
1083
|
-
updated_at: z.string().openapi({
|
|
1084
|
-
description: 'Timestamp when booking was updated',
|
|
1085
|
-
example: '2025-12-23T10:30:00.000Z'
|
|
1086
|
-
}),
|
|
1087
|
-
updated_by: z.string().nullable().openapi({
|
|
1088
|
-
description: 'ID of the user who updated the booking',
|
|
1089
|
-
example: 'user-123'
|
|
1090
|
-
})
|
|
1091
|
-
})
|
|
1092
|
-
.openapi('UpdatePhaseBookingData');
|
|
1093
|
-
export const updatePhaseBookingResponseSchema = createMessageDataResponseSchema(updatePhaseBookingDataSchema, 'UpdatePhaseBookingResponse', 'Phase booking updated successfully', 'Details of the updated booking');
|
|
1094
|
-
// ------------------------------
|
|
1095
|
-
// Booking with nested relations schema for QR generation
|
|
1096
|
-
// ------------------------------
|
|
1097
|
-
export const bookingWithRelationsSchema = z
|
|
1098
|
-
.object({
|
|
1099
|
-
id: z.number(),
|
|
1100
|
-
status: z.string(),
|
|
1101
|
-
qr_token: z.string().nullable(),
|
|
1102
|
-
booking_date: z.string(),
|
|
1103
|
-
start_time: z.string(),
|
|
1104
|
-
end_time: z.string(),
|
|
1105
|
-
company_role: z.string().nullable(),
|
|
1106
|
-
company: z.record(z.string(), z.unknown()).nullable(),
|
|
1107
|
-
vehicle: z.record(z.string(), z.unknown()).nullable(),
|
|
1108
|
-
is_active: z.boolean(),
|
|
1109
|
-
created_at: z.string(),
|
|
1110
|
-
updated_at: z.string(),
|
|
1111
|
-
phase_slot_schedules: z.object({
|
|
1112
|
-
id: z.number(),
|
|
1113
|
-
phase_slot_schedule_type: z.string(),
|
|
1114
|
-
phase_slots: z.object({
|
|
1115
|
-
id: z.number(),
|
|
1116
|
-
events: z.object({
|
|
1117
|
-
id: z.number(),
|
|
1118
|
-
name: z.string(),
|
|
1119
|
-
code: z.string(),
|
|
1120
|
-
venue_id: z.number().nullable(),
|
|
1121
|
-
banner: z.record(z.string(), z.unknown()).nullable(),
|
|
1122
|
-
venues: z
|
|
1123
|
-
.object({
|
|
1124
|
-
id: z.number(),
|
|
1125
|
-
name: z.string()
|
|
1126
|
-
})
|
|
1127
|
-
.nullable()
|
|
1128
|
-
})
|
|
1129
|
-
})
|
|
1130
|
-
})
|
|
1131
|
-
})
|
|
1132
|
-
.openapi('BookingWithRelations');
|
|
1133
|
-
// ======================================================================
|
|
1134
|
-
// PARKING BOOKING SCHEMAS (New naming convention)
|
|
1135
|
-
// These schemas use the new parking_area naming to match the database
|
|
1136
|
-
// ======================================================================
|
|
1137
|
-
// ------------------------------
|
|
1138
|
-
// Parking Booking Schema (matches parking_bookings table)
|
|
1139
|
-
// ------------------------------
|
|
1140
|
-
/**
|
|
1141
|
-
* Parking area schedule schema (from database response)
|
|
1142
|
-
* Uses new column names: parking_area_id, parking_area_schedule_type
|
|
1143
|
-
*/
|
|
1144
|
-
export const parkingAreaScheduleSchemaForBooking = z
|
|
1145
|
-
.object({
|
|
1146
|
-
id: z.number().int().positive().openapi({
|
|
1147
|
-
description: 'Unique identifier for the schedule',
|
|
1148
|
-
example: 1
|
|
1149
|
-
}),
|
|
1150
|
-
date: z.string().openapi({
|
|
1151
|
-
description: 'Date of the schedule (YYYY-MM-DD format)',
|
|
1152
|
-
example: '2025-12-15'
|
|
1153
|
-
}),
|
|
1154
|
-
start_time: z.string().openapi({
|
|
1155
|
-
description: 'Start time (HH:MM format)',
|
|
1156
|
-
example: '06:00'
|
|
1157
|
-
}),
|
|
1158
|
-
end_time: z.string().openapi({
|
|
1159
|
-
description: 'End time (HH:MM format)',
|
|
1160
|
-
example: '09:00'
|
|
1161
|
-
}),
|
|
1162
|
-
duration: z.number().openapi({
|
|
1163
|
-
description: 'Duration in minutes',
|
|
1164
|
-
example: 180
|
|
1165
|
-
}),
|
|
1166
|
-
parking_area_id: z.number().int().positive().openapi({
|
|
1167
|
-
description: 'ID of the associated parking area',
|
|
1168
|
-
example: 101
|
|
1169
|
-
}),
|
|
1170
|
-
parking_area_schedule_type: z
|
|
1171
|
-
.enum([ParkingAreaScheduleType.ASSEMBLY, ParkingAreaScheduleType.DISMANTLING])
|
|
1172
|
-
.openapi({
|
|
1173
|
-
description: 'Type of schedule',
|
|
1174
|
-
example: ParkingAreaScheduleType.ASSEMBLY
|
|
1175
|
-
}),
|
|
1176
|
-
company_role: z.string().nullable().openapi({
|
|
1177
|
-
description: 'Company role allowed for this schedule',
|
|
1178
|
-
example: 'exhibitor'
|
|
1179
|
-
}),
|
|
1180
|
-
created_at: z.string().openapi({
|
|
1181
|
-
description: 'Timestamp when schedule was created',
|
|
1182
|
-
example: '2025-12-09T10:00:00.000Z'
|
|
1183
|
-
}),
|
|
1184
|
-
updated_at: z.string().openapi({
|
|
1185
|
-
description: 'Timestamp when schedule was updated',
|
|
1186
|
-
example: '2025-12-09T10:30:00.000Z'
|
|
1187
|
-
}),
|
|
1188
|
-
created_by: z.string().uuid().nullable().openapi({
|
|
1189
|
-
description: 'UUID of user who created the schedule',
|
|
1190
|
-
example: '550e8400-e29b-41d4-a716-446655440000'
|
|
1191
|
-
}),
|
|
1192
|
-
updated_by: z.string().uuid().nullable().openapi({
|
|
1193
|
-
description: 'UUID of user who last updated the schedule',
|
|
1194
|
-
example: '550e8400-e29b-41d4-a716-446655440000'
|
|
1195
|
-
})
|
|
1196
|
-
})
|
|
1197
|
-
.openapi('ParkingAreaScheduleForBooking');
|
|
1198
|
-
/**
|
|
1199
|
-
* Parking booking schema (matches parking_bookings table)
|
|
1200
|
-
* Uses new column name: parking_area_schedule_id
|
|
1201
|
-
*/
|
|
1202
|
-
export const parkingBookingSchema = z
|
|
1203
|
-
.object({
|
|
1204
|
-
id: z.number().openapi({
|
|
1205
|
-
description: 'Booking ID',
|
|
1206
|
-
example: 1
|
|
1207
|
-
}),
|
|
1208
|
-
parking_area_schedule_id: z.number().openapi({
|
|
1209
|
-
description: 'ID of the parking area schedule',
|
|
1210
|
-
example: 456
|
|
1211
|
-
}),
|
|
1212
|
-
status: z.enum(BookingStatus).openapi({
|
|
1213
|
-
description: 'Booking status',
|
|
1214
|
-
example: BookingStatus.BOOKED
|
|
1215
|
-
}),
|
|
1216
|
-
is_active: z.boolean().openapi({
|
|
1217
|
-
description: 'Whether the booking is active',
|
|
1218
|
-
example: true
|
|
1219
|
-
}),
|
|
1220
|
-
created_at: z.string().openapi({
|
|
1221
|
-
description: 'Creation timestamp',
|
|
1222
|
-
example: '2025-12-20T10:30:00Z'
|
|
1223
|
-
}),
|
|
1224
|
-
updated_at: z.string().openapi({
|
|
1225
|
-
description: 'Last update timestamp',
|
|
1226
|
-
example: '2025-12-20T10:30:00Z'
|
|
1227
|
-
}),
|
|
1228
|
-
created_by: z.string().nullable().openapi({
|
|
1229
|
-
description: 'User ID who created the booking',
|
|
1230
|
-
example: 'user-uuid-123'
|
|
1231
|
-
}),
|
|
1232
|
-
updated_by: z.string().nullable().openapi({
|
|
1233
|
-
description: 'User ID who last updated the booking',
|
|
1234
|
-
example: 'user-uuid-123'
|
|
1235
|
-
}),
|
|
1236
|
-
booking_date: z.string().nullable().openapi({
|
|
1237
|
-
description: 'Date of the booking',
|
|
1238
|
-
example: '2025-12-15'
|
|
1239
|
-
}),
|
|
1240
|
-
start_time: z.string().nullable().openapi({
|
|
1241
|
-
description: 'Start time of the booking',
|
|
1242
|
-
example: '08:00'
|
|
1243
|
-
}),
|
|
1244
|
-
end_time: z.string().nullable().openapi({
|
|
1245
|
-
description: 'End time of the booking',
|
|
1246
|
-
example: '08:30'
|
|
1247
|
-
}),
|
|
1248
|
-
company: z.record(z.string(), z.unknown()).nullable().optional().openapi({
|
|
1249
|
-
description: 'Company details (JSONB)'
|
|
1250
|
-
}),
|
|
1251
|
-
vehicle: z.record(z.string(), z.unknown()).nullable().optional().openapi({
|
|
1252
|
-
description: 'Vehicle details (JSONB)'
|
|
1253
|
-
}),
|
|
1254
|
-
// Include the schedule details when joined
|
|
1255
|
-
parking_area_schedule: parkingAreaScheduleSchemaForBooking.optional().openapi({
|
|
1256
|
-
description: 'Associated parking area schedule details'
|
|
1257
|
-
})
|
|
1258
|
-
})
|
|
1259
|
-
.openapi('ParkingBooking');
|
|
1260
|
-
// ------------------------------
|
|
1261
|
-
// Create Parking Booking Schemas
|
|
1262
|
-
// ------------------------------
|
|
1263
|
-
export const createParkingBookingBodySchema = z
|
|
1264
|
-
.object({
|
|
1265
|
-
event_id: z.number().int().positive().openapi({
|
|
1266
|
-
description: 'ID of the event to create the booking for',
|
|
1267
|
-
example: 1
|
|
1268
|
-
}),
|
|
1269
|
-
parking_area_id: z.number().int().positive().openapi({
|
|
1270
|
-
description: 'ID of the parking area',
|
|
1271
|
-
example: 101
|
|
1272
|
-
}),
|
|
1273
|
-
request_type: z
|
|
1274
|
-
.enum([ParkingAreaScheduleType.ASSEMBLY, ParkingAreaScheduleType.DISMANTLING])
|
|
1275
|
-
.default(ParkingAreaScheduleType.ASSEMBLY)
|
|
1276
|
-
.openapi({
|
|
1277
|
-
description: 'Type of request (assembly or dismantling)',
|
|
1278
|
-
example: ParkingAreaScheduleType.ASSEMBLY
|
|
1279
|
-
}),
|
|
1280
|
-
selected_date: z.string().min(1, 'Date is required').openapi({
|
|
1281
|
-
description: 'Selected date (YYYY-MM-DD)',
|
|
1282
|
-
example: '2025-12-15'
|
|
1283
|
-
}),
|
|
1284
|
-
selected_time: z.string().min(1, 'Time is required').openapi({
|
|
1285
|
-
description: 'Selected time slot (HH:MM)',
|
|
1286
|
-
example: '08:00'
|
|
1287
|
-
}),
|
|
1288
|
-
company: companyDetailsSchema.openapi({
|
|
1289
|
-
description: 'Company details including stand, contact, and driver info'
|
|
1290
|
-
}),
|
|
1291
|
-
vehicle: vehicleDetailsSchema.openapi({
|
|
1292
|
-
description: 'Vehicle details'
|
|
1293
|
-
})
|
|
1294
|
-
})
|
|
1295
|
-
.openapi('CreateParkingBookingBody');
|
|
1296
|
-
export const createParkingBookingDataSchema = z
|
|
1297
|
-
.object({
|
|
1298
|
-
booking_id: z.number().openapi({
|
|
1299
|
-
description: 'ID of the created booking',
|
|
1300
|
-
example: 789
|
|
1301
|
-
}),
|
|
1302
|
-
parking_area_schedule_id: z.number().openapi({
|
|
1303
|
-
description: 'ID of the parking area schedule',
|
|
1304
|
-
example: 456
|
|
1305
|
-
}),
|
|
1306
|
-
parking_area_id: z.number().openapi({
|
|
1307
|
-
description: 'ID of the parking area',
|
|
1308
|
-
example: 101
|
|
1309
|
-
}),
|
|
1310
|
-
status: z.enum(BookingStatus).openapi({
|
|
1311
|
-
description: 'Booking status',
|
|
1312
|
-
example: BookingStatus.BOOKED
|
|
1313
|
-
}),
|
|
1314
|
-
booking_date: z.string().openapi({
|
|
1315
|
-
description: 'Booking date',
|
|
1316
|
-
example: '2025-12-15'
|
|
1317
|
-
}),
|
|
1318
|
-
start_time: z.string().openapi({
|
|
1319
|
-
description: 'Start time',
|
|
1320
|
-
example: '08:00'
|
|
1321
|
-
}),
|
|
1322
|
-
end_time: z.string().openapi({
|
|
1323
|
-
description: 'End time',
|
|
1324
|
-
example: '08:30'
|
|
1325
|
-
}),
|
|
1326
|
-
company: companyDetailsSchema.openapi({
|
|
1327
|
-
description: 'Company details'
|
|
1328
|
-
}),
|
|
1329
|
-
vehicle: vehicleDetailsSchema.openapi({
|
|
1330
|
-
description: 'Vehicle details'
|
|
1331
|
-
}),
|
|
1332
|
-
created_at: z.string().openapi({
|
|
1333
|
-
description: 'Timestamp when booking was created',
|
|
1334
|
-
example: '2025-12-20T10:30:00.000Z'
|
|
1335
|
-
}),
|
|
1336
|
-
created_by: z.string().nullable().openapi({
|
|
1337
|
-
description: 'ID of the user who created the booking',
|
|
1338
|
-
example: 'user-123'
|
|
1339
|
-
})
|
|
1340
|
-
})
|
|
1341
|
-
.openapi('CreateParkingBookingData');
|
|
1342
|
-
export const createParkingBookingResponseSchema = createMessageDataResponseSchema(createParkingBookingDataSchema, 'CreateParkingBookingResponse', 'Parking booking created successfully', 'Details of the created parking booking');
|
|
1343
|
-
// ------------------------------
|
|
1344
|
-
// Parking Bookings List Response
|
|
1345
|
-
// ------------------------------
|
|
1346
|
-
export const parkingBookingsDataSchema = z
|
|
1347
|
-
.object({
|
|
1348
|
-
event_id: z.number().openapi({
|
|
1349
|
-
description: 'Event ID',
|
|
1350
|
-
example: 1
|
|
1351
|
-
}),
|
|
1352
|
-
event_code: z.string().openapi({
|
|
1353
|
-
description: 'Event code',
|
|
1354
|
-
example: 'COEC2025'
|
|
1355
|
-
}),
|
|
1356
|
-
event_name: z.string().openapi({
|
|
1357
|
-
description: 'Event name',
|
|
1358
|
-
example: 'COEC 2025'
|
|
1359
|
-
}),
|
|
1360
|
-
bookings: z.array(parkingBookingSchema).openapi({
|
|
1361
|
-
description: 'List of parking bookings'
|
|
1362
|
-
}),
|
|
1363
|
-
total_count: z.number().openapi({
|
|
1364
|
-
description: 'Total number of bookings',
|
|
1365
|
-
example: 25
|
|
1366
|
-
})
|
|
1367
|
-
})
|
|
1368
|
-
.openapi('ParkingBookingsData');
|
|
1369
|
-
export const parkingBookingsResponseSchema = createSuccessResponseSchema(parkingBookingsDataSchema, 'ParkingBookingsResponse', 'Parking bookings data with parking area details');
|