@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
|
@@ -0,0 +1,734 @@
|
|
|
1
|
+
// packages/phasing-schemas/src/parkingBooking.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 { parkingAreaScheduleSchema } from './parkingArea.js';
|
|
7
|
+
// PostGIS geometry schema (GeoJSON-like structure)
|
|
8
|
+
export const geometrySchema = z
|
|
9
|
+
.object({
|
|
10
|
+
type: z.enum([
|
|
11
|
+
'Polygon',
|
|
12
|
+
'MultiPolygon',
|
|
13
|
+
'Point',
|
|
14
|
+
'LineString',
|
|
15
|
+
'MultiLineString',
|
|
16
|
+
'MultiPoint'
|
|
17
|
+
]),
|
|
18
|
+
coordinates: z.array(z.unknown()),
|
|
19
|
+
crs: z
|
|
20
|
+
.object({
|
|
21
|
+
type: z.literal('name'),
|
|
22
|
+
properties: z.object({
|
|
23
|
+
name: z.string()
|
|
24
|
+
})
|
|
25
|
+
})
|
|
26
|
+
.optional()
|
|
27
|
+
})
|
|
28
|
+
.nullable()
|
|
29
|
+
.openapi({
|
|
30
|
+
description: 'PostGIS geometry object (GeoJSON format)',
|
|
31
|
+
example: {
|
|
32
|
+
type: 'Polygon',
|
|
33
|
+
coordinates: [
|
|
34
|
+
[
|
|
35
|
+
[2.3522, 48.8566],
|
|
36
|
+
[2.3532, 48.8566],
|
|
37
|
+
[2.3532, 48.8576],
|
|
38
|
+
[2.3522, 48.8576],
|
|
39
|
+
[2.3522, 48.8566]
|
|
40
|
+
]
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
// ------------------------------
|
|
45
|
+
// Query parameters schema
|
|
46
|
+
// ------------------------------
|
|
47
|
+
export const getEventBookingsQuerySchema = z
|
|
48
|
+
.object({
|
|
49
|
+
event_code: z.string().min(1, 'Event code is required').openapi({
|
|
50
|
+
description: 'Unique code identifying the event',
|
|
51
|
+
example: 'COEC2025'
|
|
52
|
+
}),
|
|
53
|
+
seller_id: z
|
|
54
|
+
.string()
|
|
55
|
+
.min(1, 'Seller ID is required')
|
|
56
|
+
.transform(val => parseInt(val, 10))
|
|
57
|
+
.refine(val => !isNaN(val) && val > 0, { message: 'Seller ID must be positive' })
|
|
58
|
+
.openapi({
|
|
59
|
+
description: 'ID of the seller (must be a positive integer)',
|
|
60
|
+
example: '1'
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
.extend(paginationSchema.shape)
|
|
64
|
+
.openapi('GetEventBookingsQuery');
|
|
65
|
+
export const closeEventParamsSchema = z
|
|
66
|
+
.object({
|
|
67
|
+
eventId: z
|
|
68
|
+
.string()
|
|
69
|
+
.min(1, 'Event ID is required')
|
|
70
|
+
.transform(val => parseInt(val, 10))
|
|
71
|
+
.refine(val => !isNaN(val) && val > 0, { message: 'Event ID must be positive' })
|
|
72
|
+
.openapi({
|
|
73
|
+
description: 'The ID of the event to close',
|
|
74
|
+
example: '1'
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
.openapi('CloseEventParams');
|
|
78
|
+
export const closeEventBodySchema = z
|
|
79
|
+
.object({
|
|
80
|
+
reason: z.string().optional().openapi({
|
|
81
|
+
description: 'Optional reason for closing the event phase (for audit purposes)',
|
|
82
|
+
example: 'Event phase completed - moving to next stage'
|
|
83
|
+
})
|
|
84
|
+
})
|
|
85
|
+
.openapi('CloseEventBody');
|
|
86
|
+
export const parkingBookingSchema = z.object({
|
|
87
|
+
id: z.number(),
|
|
88
|
+
parking_area_schedule_id: z.number(),
|
|
89
|
+
status: z.enum(BookingStatus),
|
|
90
|
+
is_active: z.boolean(),
|
|
91
|
+
created_at: z.string(),
|
|
92
|
+
updated_at: z.string(),
|
|
93
|
+
created_by: z.string().nullable(),
|
|
94
|
+
updated_by: z.string().nullable(),
|
|
95
|
+
booking_date: z.string().nullable(),
|
|
96
|
+
start_time: z.string().nullable(),
|
|
97
|
+
end_time: z.string().nullable(),
|
|
98
|
+
company_role: z.string().nullable(),
|
|
99
|
+
company: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
100
|
+
vehicle: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
101
|
+
// Include the schedule details
|
|
102
|
+
parking_area_schedule: parkingAreaScheduleSchema.optional()
|
|
103
|
+
});
|
|
104
|
+
export const companyDetailsSchema = z
|
|
105
|
+
.object({
|
|
106
|
+
hall: z.string().min(1, 'Hall is required').openapi({
|
|
107
|
+
description: 'Hall location',
|
|
108
|
+
example: 'Hall 1'
|
|
109
|
+
}),
|
|
110
|
+
stand_number: z.string().min(1, 'Stand number is required').openapi({
|
|
111
|
+
description: 'Stand number',
|
|
112
|
+
example: 'A-123'
|
|
113
|
+
}),
|
|
114
|
+
company_name: z.string().min(1, 'Company name is required').openapi({
|
|
115
|
+
description: 'Company name',
|
|
116
|
+
example: 'Acme Corp'
|
|
117
|
+
}),
|
|
118
|
+
business: z.string().min(1, 'Business is required').openapi({
|
|
119
|
+
description: 'Type of business',
|
|
120
|
+
example: 'Technology'
|
|
121
|
+
}),
|
|
122
|
+
departure_city: z.string().min(1, 'Departure city is required').openapi({
|
|
123
|
+
description: 'City of departure',
|
|
124
|
+
example: 'Paris'
|
|
125
|
+
}),
|
|
126
|
+
contact_name: z.string().min(1, 'Contact name is required').openapi({
|
|
127
|
+
description: 'Contact person name',
|
|
128
|
+
example: 'John Doe'
|
|
129
|
+
}),
|
|
130
|
+
email: z.email('Valid email is required').openapi({
|
|
131
|
+
description: 'Contact email',
|
|
132
|
+
example: 'john.doe@acme.com'
|
|
133
|
+
}),
|
|
134
|
+
phone: z.string().min(1, 'Phone is required').openapi({
|
|
135
|
+
description: 'Contact phone number',
|
|
136
|
+
example: '+33 1 23 45 67 89'
|
|
137
|
+
}),
|
|
138
|
+
driver_name: z.string().min(1, 'Driver name is required').openapi({
|
|
139
|
+
description: 'Driver name',
|
|
140
|
+
example: 'Jean Martin'
|
|
141
|
+
}),
|
|
142
|
+
driver_phone: z.string().min(1, 'Driver phone is required').openapi({
|
|
143
|
+
description: 'Driver phone number',
|
|
144
|
+
example: '+33 6 12 34 56 78'
|
|
145
|
+
}),
|
|
146
|
+
transport_company: z.string().min(1, 'Transport company is required').openapi({
|
|
147
|
+
description: 'Transport company name',
|
|
148
|
+
example: 'Fast Transport Ltd'
|
|
149
|
+
})
|
|
150
|
+
})
|
|
151
|
+
.openapi('CompanyDetails');
|
|
152
|
+
export const vehicleDetailsSchema = z
|
|
153
|
+
.object({
|
|
154
|
+
vehicle_type: z.string().min(1, 'Vehicle type is required').openapi({
|
|
155
|
+
description: 'Type of vehicle',
|
|
156
|
+
example: 'Truck'
|
|
157
|
+
}),
|
|
158
|
+
unloading_method: z.string().min(1, 'Unloading method is required').openapi({
|
|
159
|
+
description: 'Method of unloading',
|
|
160
|
+
example: 'Manual'
|
|
161
|
+
}),
|
|
162
|
+
license_plate: z.string().min(1, 'License plate is required').openapi({
|
|
163
|
+
description: 'Vehicle license plate',
|
|
164
|
+
example: 'AB-123-CD'
|
|
165
|
+
}),
|
|
166
|
+
trailer_registration: z.string().optional().openapi({
|
|
167
|
+
description: 'Trailer registration number',
|
|
168
|
+
example: 'TR-456-EF'
|
|
169
|
+
})
|
|
170
|
+
})
|
|
171
|
+
.openapi('VehicleDetails');
|
|
172
|
+
export const eventBookingsDataSchema = z
|
|
173
|
+
.object({
|
|
174
|
+
event_id: z.number(),
|
|
175
|
+
event_code: z.string(),
|
|
176
|
+
event_name: z.string(),
|
|
177
|
+
bookings: z.array(parkingBookingSchema),
|
|
178
|
+
total_count: z.number()
|
|
179
|
+
})
|
|
180
|
+
.openapi('EventBookingsData');
|
|
181
|
+
export const eventBookingsResponseSchema = createSuccessResponseSchema(eventBookingsDataSchema, 'EventBookingsResponse', 'Event bookings data with parking area details');
|
|
182
|
+
export const closeEventDataSchema = z
|
|
183
|
+
.object({
|
|
184
|
+
event_id: z.number().openapi({
|
|
185
|
+
description: 'ID of the close event',
|
|
186
|
+
example: 1
|
|
187
|
+
}),
|
|
188
|
+
event_code: z.string().nullable().openapi({
|
|
189
|
+
description: 'Code of the close event',
|
|
190
|
+
example: 'EVENT2025'
|
|
191
|
+
}),
|
|
192
|
+
event_name: z.string().openapi({
|
|
193
|
+
description: 'Name of the close event',
|
|
194
|
+
example: 'Annual Trade Show 2025'
|
|
195
|
+
}),
|
|
196
|
+
is_active: z.boolean().openapi({
|
|
197
|
+
description: 'Active status of the event',
|
|
198
|
+
example: false
|
|
199
|
+
}),
|
|
200
|
+
close_at: z.string().openapi({
|
|
201
|
+
description: 'Timestamp when the event was closed',
|
|
202
|
+
example: '2025-12-04T10:30:00.000Z'
|
|
203
|
+
}),
|
|
204
|
+
close_by: z.string().nullable().openapi({
|
|
205
|
+
description: 'ID of the user who closed the event',
|
|
206
|
+
example: null
|
|
207
|
+
}),
|
|
208
|
+
reason: z.string().nullable().openapi({
|
|
209
|
+
description: 'Reason for closing the event',
|
|
210
|
+
example: 'Event cancelled due to logistical issues'
|
|
211
|
+
})
|
|
212
|
+
})
|
|
213
|
+
.openapi('CloseEventData');
|
|
214
|
+
export const closeEventResponseSchema = createMessageDataResponseSchema(closeEventDataSchema, 'CloseEventResponse', 'Event phase closed successfully', 'Details of the closed event phase');
|
|
215
|
+
export const confirmAccessDataSchema = z.object({
|
|
216
|
+
bookingId: z.coerce.number().int().positive({
|
|
217
|
+
message: 'Booking ID must be a positive integer'
|
|
218
|
+
})
|
|
219
|
+
});
|
|
220
|
+
export const confirmAccessResponseSchema = z.object({
|
|
221
|
+
success: z.boolean(),
|
|
222
|
+
message: z.string(),
|
|
223
|
+
data: z.object({
|
|
224
|
+
booking_id: z.number(),
|
|
225
|
+
scanned_at: z.string()
|
|
226
|
+
})
|
|
227
|
+
});
|
|
228
|
+
// ------------------------------
|
|
229
|
+
// Check Slot Availability schemas
|
|
230
|
+
// ------------------------------
|
|
231
|
+
export const checkSlotAvailabilityBodySchema = z
|
|
232
|
+
.object({
|
|
233
|
+
schedule_id: z.number().positive().openapi({
|
|
234
|
+
description: 'The ID of the parking area schedule',
|
|
235
|
+
example: 1
|
|
236
|
+
}),
|
|
237
|
+
date: z
|
|
238
|
+
.string()
|
|
239
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/, 'Date must be in YYYY-MM-DD format')
|
|
240
|
+
.openapi({
|
|
241
|
+
description: 'The date to check availability (YYYY-MM-DD)',
|
|
242
|
+
example: '2025-12-15'
|
|
243
|
+
}),
|
|
244
|
+
start_time: z
|
|
245
|
+
.string()
|
|
246
|
+
.regex(/^\d{2}:\d{2}$/, 'Time must be in HH:MM format')
|
|
247
|
+
.openapi({
|
|
248
|
+
description: 'The start time to check availability (HH:MM)',
|
|
249
|
+
example: '08:00'
|
|
250
|
+
}),
|
|
251
|
+
company_role: z.string().min(1, 'Company role is required').openapi({
|
|
252
|
+
description: 'Company role to check availability for',
|
|
253
|
+
example: 'exhibitor'
|
|
254
|
+
})
|
|
255
|
+
})
|
|
256
|
+
.openapi('CheckSlotAvailabilityBody');
|
|
257
|
+
export const checkSlotAvailabilityDataSchema = z
|
|
258
|
+
.object({
|
|
259
|
+
schedule_id: z.number().openapi({
|
|
260
|
+
description: 'ID of the parking area schedule',
|
|
261
|
+
example: 1
|
|
262
|
+
}),
|
|
263
|
+
date: z.string().openapi({
|
|
264
|
+
description: 'Date checked',
|
|
265
|
+
example: '2025-12-15'
|
|
266
|
+
}),
|
|
267
|
+
start_time: z.string().openapi({
|
|
268
|
+
description: 'Time slot checked',
|
|
269
|
+
example: '08:00'
|
|
270
|
+
}),
|
|
271
|
+
is_available: z.boolean().openapi({
|
|
272
|
+
description: 'Whether the slot is available for booking',
|
|
273
|
+
example: true
|
|
274
|
+
}),
|
|
275
|
+
max_capacity: z.number().openapi({
|
|
276
|
+
description: 'Maximum booking capacity',
|
|
277
|
+
example: 5
|
|
278
|
+
}),
|
|
279
|
+
current_bookings: z.number().openapi({
|
|
280
|
+
description: 'Current number of total bookings',
|
|
281
|
+
example: 3
|
|
282
|
+
}),
|
|
283
|
+
confirmed_bookings: z.number().openapi({
|
|
284
|
+
description: 'Current number of confirmed bookings',
|
|
285
|
+
example: 1
|
|
286
|
+
}),
|
|
287
|
+
available_capacity: z.number().openapi({
|
|
288
|
+
description: 'Remaining available capacity',
|
|
289
|
+
example: 2
|
|
290
|
+
})
|
|
291
|
+
})
|
|
292
|
+
.openapi('CheckSlotAvailabilityData');
|
|
293
|
+
export const checkSlotAvailabilityResponseSchema = createSuccessResponseSchema(checkSlotAvailabilityDataSchema, 'CheckSlotAvailabilityResponse', 'Slot availability information with capacity details');
|
|
294
|
+
// ------------------------------
|
|
295
|
+
// QR Code Generation schemas
|
|
296
|
+
// ------------------------------
|
|
297
|
+
export const bookingDetailsDataSchema = z
|
|
298
|
+
.object({
|
|
299
|
+
qr_token: z.string().nullable().openapi({
|
|
300
|
+
description: 'QR token for verification',
|
|
301
|
+
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
|
|
302
|
+
}),
|
|
303
|
+
id: z.number().openapi({
|
|
304
|
+
description: 'ID of the booking',
|
|
305
|
+
example: 123
|
|
306
|
+
}),
|
|
307
|
+
booking_id: z.number().openapi({
|
|
308
|
+
description: 'ID of the booking',
|
|
309
|
+
example: 123
|
|
310
|
+
}),
|
|
311
|
+
status: z.string().openapi({
|
|
312
|
+
description: 'Booking status',
|
|
313
|
+
example: 'confirmed'
|
|
314
|
+
}),
|
|
315
|
+
booking_date: z.string().openapi({
|
|
316
|
+
description: 'Date of the booking',
|
|
317
|
+
example: '2025-12-15'
|
|
318
|
+
}),
|
|
319
|
+
start_time: z.string().openapi({
|
|
320
|
+
description: 'Start time of the booking',
|
|
321
|
+
example: '08:00'
|
|
322
|
+
}),
|
|
323
|
+
end_time: z.string().openapi({
|
|
324
|
+
description: 'End time of the booking',
|
|
325
|
+
example: '08:30'
|
|
326
|
+
}),
|
|
327
|
+
company_role: z.string().nullable().openapi({
|
|
328
|
+
description: 'Company role for the booking',
|
|
329
|
+
example: 'exhibitor'
|
|
330
|
+
}),
|
|
331
|
+
company: companyDetailsSchema.openapi({
|
|
332
|
+
description: 'Company details'
|
|
333
|
+
}),
|
|
334
|
+
vehicle: vehicleDetailsSchema.openapi({
|
|
335
|
+
description: 'Vehicle details'
|
|
336
|
+
}),
|
|
337
|
+
event_id: z.number().openapi({
|
|
338
|
+
description: 'ID of the event',
|
|
339
|
+
example: 1
|
|
340
|
+
}),
|
|
341
|
+
event_name: z.string().openapi({
|
|
342
|
+
description: 'Name of the event',
|
|
343
|
+
example: 'Paris Fashion Week 2025'
|
|
344
|
+
}),
|
|
345
|
+
event_code: z.string().openapi({
|
|
346
|
+
description: 'Code of the event',
|
|
347
|
+
example: 'PFW2025'
|
|
348
|
+
}),
|
|
349
|
+
venue_id: z.number().nullable().openapi({
|
|
350
|
+
description: 'ID of the venue',
|
|
351
|
+
example: 1
|
|
352
|
+
}),
|
|
353
|
+
venue_name: z.string().nullable().openapi({
|
|
354
|
+
description: 'Name of the venue',
|
|
355
|
+
example: 'Paris Expo Porte de Versailles'
|
|
356
|
+
}),
|
|
357
|
+
request_type: z.string().openapi({
|
|
358
|
+
description: 'Type of parking area schedule (assembly/dismantling)',
|
|
359
|
+
example: 'assembly'
|
|
360
|
+
}),
|
|
361
|
+
duration: z.number().openapi({
|
|
362
|
+
description: 'Duration of the booking in minutes',
|
|
363
|
+
example: 30
|
|
364
|
+
}),
|
|
365
|
+
parking_area_schedule_id: z.number().openapi({
|
|
366
|
+
description: 'ID of the parking area schedule',
|
|
367
|
+
example: 456
|
|
368
|
+
}),
|
|
369
|
+
banner: documentSchema.nullable().openapi({
|
|
370
|
+
description: 'Event banner document',
|
|
371
|
+
example: {
|
|
372
|
+
url: 'https://example.com/event-banner.jpg',
|
|
373
|
+
name: 'event-banner.jpg',
|
|
374
|
+
type: 'image/jpeg'
|
|
375
|
+
}
|
|
376
|
+
}),
|
|
377
|
+
created_at: z.string().openapi({
|
|
378
|
+
description: 'Timestamp when booking was created',
|
|
379
|
+
example: '2025-12-05T10:30:00.000Z'
|
|
380
|
+
}),
|
|
381
|
+
updated_at: z.string().openapi({
|
|
382
|
+
description: 'Timestamp when booking was last updated',
|
|
383
|
+
example: '2025-12-05T10:30:00.000Z'
|
|
384
|
+
})
|
|
385
|
+
})
|
|
386
|
+
.openapi('BookingDetailsData');
|
|
387
|
+
// ------------------------------
|
|
388
|
+
// Create Parking Booking schemas
|
|
389
|
+
// ------------------------------
|
|
390
|
+
// Request schema
|
|
391
|
+
export const createParkingBookingBodySchema = z
|
|
392
|
+
.object({
|
|
393
|
+
parking_area_schedule_id: z.number().int().positive().openapi({
|
|
394
|
+
description: 'ID of the parking area schedule to book',
|
|
395
|
+
example: 1
|
|
396
|
+
}),
|
|
397
|
+
// Company details
|
|
398
|
+
company: companyDetailsSchema.openapi({
|
|
399
|
+
description: 'Company details including stand, contact, and driver info'
|
|
400
|
+
}),
|
|
401
|
+
company_role: z.string().min(1).openapi({
|
|
402
|
+
description: 'Company role (e.g., exhibitor, contractor, organizer)',
|
|
403
|
+
example: 'exhibitor'
|
|
404
|
+
}),
|
|
405
|
+
// Vehicle details
|
|
406
|
+
vehicle: vehicleDetailsSchema.openapi({
|
|
407
|
+
description: 'Vehicle details'
|
|
408
|
+
}),
|
|
409
|
+
vehicle_type: z.enum(['PL', 'VUL', 'VL']).openapi({
|
|
410
|
+
description: 'Vehicle type: PL (poids lourd), VUL (véhicule utilitaire léger), VL (véhicule léger)',
|
|
411
|
+
example: 'PL'
|
|
412
|
+
}),
|
|
413
|
+
booking_date: z
|
|
414
|
+
.string()
|
|
415
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
|
416
|
+
.openapi({
|
|
417
|
+
description: 'Booking date (YYYY-MM-DD)',
|
|
418
|
+
example: '2025-12-25'
|
|
419
|
+
}),
|
|
420
|
+
start_time: z
|
|
421
|
+
.string()
|
|
422
|
+
.regex(/^\d{2}:\d{2}$/)
|
|
423
|
+
.openapi({
|
|
424
|
+
description: 'Start time (HH:MM)',
|
|
425
|
+
example: '06:00'
|
|
426
|
+
}),
|
|
427
|
+
end_time: z
|
|
428
|
+
.string()
|
|
429
|
+
.regex(/^\d{2}:\d{2}$/)
|
|
430
|
+
.openapi({
|
|
431
|
+
description: 'End time (HH:MM)',
|
|
432
|
+
example: '09:00'
|
|
433
|
+
})
|
|
434
|
+
})
|
|
435
|
+
.openapi('CreateParkingBookingBody');
|
|
436
|
+
// Response schema
|
|
437
|
+
export const createParkingBookingDataSchema = z
|
|
438
|
+
.object({
|
|
439
|
+
id: z.number(),
|
|
440
|
+
parking_area_schedule_id: z.number(),
|
|
441
|
+
status: z.string(),
|
|
442
|
+
company_role: z.string(),
|
|
443
|
+
company: companyDetailsSchema.openapi({
|
|
444
|
+
description: 'Company details including stand, contact, and driver info'
|
|
445
|
+
}),
|
|
446
|
+
vehicle: vehicleDetailsSchema.openapi({
|
|
447
|
+
description: 'Vehicle details'
|
|
448
|
+
}),
|
|
449
|
+
vehicle_type: z.string(),
|
|
450
|
+
booking_date: z.string(),
|
|
451
|
+
start_time: z.string(),
|
|
452
|
+
end_time: z.string(),
|
|
453
|
+
created_at: z.string(),
|
|
454
|
+
created_by: z.string().nullable()
|
|
455
|
+
})
|
|
456
|
+
.openapi('CreateParkingBookingData');
|
|
457
|
+
export const createParkingBookingResponseSchema = createMessageDataResponseSchema(createParkingBookingDataSchema, 'CreateParkingBookingResponse', 'Parking booking created successfully', 'Details of the created booking');
|
|
458
|
+
// ------------------------------
|
|
459
|
+
// Update Parking Booking schemas
|
|
460
|
+
// ------------------------------
|
|
461
|
+
export const updateParkingBookingBodySchema = z
|
|
462
|
+
.object({
|
|
463
|
+
company: companyDetailsSchema.optional().openapi({
|
|
464
|
+
description: 'Updated company details'
|
|
465
|
+
}),
|
|
466
|
+
vehicle: vehicleDetailsSchema.optional().openapi({
|
|
467
|
+
description: 'Updated vehicle details'
|
|
468
|
+
}),
|
|
469
|
+
access_token: z.string().min(1, 'Access token is required').openapi({
|
|
470
|
+
description: 'Access pass token for booking verification',
|
|
471
|
+
example: 'ACCESS_1a2b3c4d5e6f7g8h_eyJib29raW5nSWQiOjF9'
|
|
472
|
+
})
|
|
473
|
+
})
|
|
474
|
+
.refine(data => data.company !== undefined || data.vehicle !== undefined, {
|
|
475
|
+
message: 'At least one field (company or vehicle) must be provided for update'
|
|
476
|
+
})
|
|
477
|
+
.openapi('UpdateParkingBookingBody');
|
|
478
|
+
export const updateParkingBookingDataSchema = z
|
|
479
|
+
.object({
|
|
480
|
+
booking_id: z.number().openapi({
|
|
481
|
+
description: 'ID of the updated booking',
|
|
482
|
+
example: 1
|
|
483
|
+
}),
|
|
484
|
+
qr_token: z.string().openapi({
|
|
485
|
+
description: 'New regenerated QR token',
|
|
486
|
+
example: 'ACCESS_1a2b3c4d5e6f7g8h_eyJib29raW5nSWQiOjF9'
|
|
487
|
+
}),
|
|
488
|
+
company: companyDetailsSchema.nullable().openapi({
|
|
489
|
+
description: 'Updated company details'
|
|
490
|
+
}),
|
|
491
|
+
vehicle: vehicleDetailsSchema.nullable().openapi({
|
|
492
|
+
description: 'Updated vehicle details'
|
|
493
|
+
}),
|
|
494
|
+
updated_at: z.string().openapi({
|
|
495
|
+
description: 'Timestamp when booking was updated',
|
|
496
|
+
example: '2025-12-23T10:30:00.000Z'
|
|
497
|
+
}),
|
|
498
|
+
updated_by: z.string().nullable().openapi({
|
|
499
|
+
description: 'ID of the user who updated the booking',
|
|
500
|
+
example: 'user-123'
|
|
501
|
+
})
|
|
502
|
+
})
|
|
503
|
+
.openapi('UpdateParkingBookingData');
|
|
504
|
+
export const updateParkingBookingResponseSchema = createMessageDataResponseSchema(updateParkingBookingDataSchema, 'UpdateParkingBookingResponse', 'Parking booking updated successfully', 'Details of the updated booking');
|
|
505
|
+
// ------------------------------
|
|
506
|
+
// Confirm Booking Schemas
|
|
507
|
+
// ------------------------------
|
|
508
|
+
// Path params schema
|
|
509
|
+
export const confirmBookingParamsSchema = z
|
|
510
|
+
.object({
|
|
511
|
+
bookingId: z
|
|
512
|
+
.string()
|
|
513
|
+
.transform(val => parseInt(val, 10))
|
|
514
|
+
.refine(val => !isNaN(val) && val > 0, {
|
|
515
|
+
message: 'Booking ID must be a positive number'
|
|
516
|
+
})
|
|
517
|
+
.openapi({
|
|
518
|
+
description: 'Parking booking ID',
|
|
519
|
+
example: '1'
|
|
520
|
+
})
|
|
521
|
+
})
|
|
522
|
+
.openapi('ConfirmBookingParams');
|
|
523
|
+
// Response schema
|
|
524
|
+
export const confirmBookingDataSchema = z
|
|
525
|
+
.object({
|
|
526
|
+
success: z.boolean(),
|
|
527
|
+
message: z.string(),
|
|
528
|
+
data: z.object({
|
|
529
|
+
id: z.number(),
|
|
530
|
+
status: z.string(),
|
|
531
|
+
parking_area_schedule_id: z.number(),
|
|
532
|
+
updated_at: z.string(),
|
|
533
|
+
updated_by: z.string()
|
|
534
|
+
})
|
|
535
|
+
})
|
|
536
|
+
.openapi('ConfirmBookingData');
|
|
537
|
+
export const confirmBookingResponseSchema = createMessageDataResponseSchema(confirmBookingDataSchema, 'ConfirmBookingResponse', 'Parking booking confirmed successfully', 'Details of the confirmed booking');
|
|
538
|
+
// ------------------------------
|
|
539
|
+
// Refuse Booking Schemas
|
|
540
|
+
// ------------------------------
|
|
541
|
+
// Path params schema
|
|
542
|
+
export const refuseBookingParamsSchema = z
|
|
543
|
+
.object({
|
|
544
|
+
bookingId: z
|
|
545
|
+
.string()
|
|
546
|
+
.transform(val => parseInt(val, 10))
|
|
547
|
+
.refine(val => !isNaN(val) && val > 0, {
|
|
548
|
+
message: 'Booking ID must be a positive number'
|
|
549
|
+
})
|
|
550
|
+
.openapi({
|
|
551
|
+
description: 'Parking booking ID',
|
|
552
|
+
example: '1'
|
|
553
|
+
})
|
|
554
|
+
})
|
|
555
|
+
.openapi('RefuseBookingParams');
|
|
556
|
+
// Response schema
|
|
557
|
+
export const refuseBookingDataSchema = z
|
|
558
|
+
.object({
|
|
559
|
+
success: z.boolean(),
|
|
560
|
+
message: z.string(),
|
|
561
|
+
data: z.object({
|
|
562
|
+
id: z.number(),
|
|
563
|
+
status: z.string(),
|
|
564
|
+
parking_area_schedule_id: z.number(),
|
|
565
|
+
updated_at: z.string(),
|
|
566
|
+
updated_by: z.string()
|
|
567
|
+
})
|
|
568
|
+
})
|
|
569
|
+
.openapi('RefuseBookingData');
|
|
570
|
+
export const refuseBookingResponseSchema = createMessageDataResponseSchema(refuseBookingDataSchema, 'RefuseBookingResponse', 'Parking booking refused successfully', 'Details of the refused booking');
|
|
571
|
+
// ------------------------------
|
|
572
|
+
// Booking with nested relations schema for QR generation
|
|
573
|
+
// ------------------------------
|
|
574
|
+
export const parkingBookingWithRelationsSchema = z
|
|
575
|
+
.object({
|
|
576
|
+
id: z.number(),
|
|
577
|
+
status: z.string(),
|
|
578
|
+
qr_token: z.string().nullable(),
|
|
579
|
+
booking_date: z.string(),
|
|
580
|
+
start_time: z.string(),
|
|
581
|
+
end_time: z.string(),
|
|
582
|
+
company_role: z.string().nullable(),
|
|
583
|
+
company: z.record(z.string(), z.unknown()).nullable(),
|
|
584
|
+
vehicle: z.record(z.string(), z.unknown()).nullable(),
|
|
585
|
+
is_active: z.boolean(),
|
|
586
|
+
created_at: z.string(),
|
|
587
|
+
updated_at: z.string(),
|
|
588
|
+
parking_area_schedules: z.object({
|
|
589
|
+
id: z.number(),
|
|
590
|
+
parking_area_schedule_type: z.string(),
|
|
591
|
+
parking_areas: z.object({
|
|
592
|
+
id: z.number(),
|
|
593
|
+
events: z.object({
|
|
594
|
+
id: z.number(),
|
|
595
|
+
name: z.string(),
|
|
596
|
+
code: z.string(),
|
|
597
|
+
venue_id: z.number().nullable(),
|
|
598
|
+
banner: z.record(z.string(), z.unknown()).nullable(),
|
|
599
|
+
venues: z
|
|
600
|
+
.object({
|
|
601
|
+
id: z.number(),
|
|
602
|
+
name: z.string()
|
|
603
|
+
})
|
|
604
|
+
.nullable()
|
|
605
|
+
})
|
|
606
|
+
})
|
|
607
|
+
})
|
|
608
|
+
})
|
|
609
|
+
.openapi('ParkingBookingWithRelations');
|
|
610
|
+
// ------------------------------
|
|
611
|
+
// QR Code Generation schemas
|
|
612
|
+
// ------------------------------
|
|
613
|
+
export const getParkingBookingDetailsParamsSchema = z
|
|
614
|
+
.object({
|
|
615
|
+
bookingId: z.coerce.number().int().positive({
|
|
616
|
+
message: 'Booking ID must be a positive integer'
|
|
617
|
+
})
|
|
618
|
+
})
|
|
619
|
+
.openapi('GetParkingBookingDetailsParams');
|
|
620
|
+
export const parkingBookingDetailsDataSchema = z
|
|
621
|
+
.object({
|
|
622
|
+
qr_token: z.string().nullable().openapi({
|
|
623
|
+
description: 'QR token for verification',
|
|
624
|
+
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
|
|
625
|
+
}),
|
|
626
|
+
id: z.number().openapi({
|
|
627
|
+
description: 'ID of the booking',
|
|
628
|
+
example: 123
|
|
629
|
+
}),
|
|
630
|
+
booking_id: z.number().openapi({
|
|
631
|
+
description: 'ID of the booking',
|
|
632
|
+
example: 123
|
|
633
|
+
}),
|
|
634
|
+
status: z.string().openapi({
|
|
635
|
+
description: 'Booking status',
|
|
636
|
+
example: 'confirmed'
|
|
637
|
+
}),
|
|
638
|
+
booking_date: z.string().openapi({
|
|
639
|
+
description: 'Date of the booking',
|
|
640
|
+
example: '2025-12-15'
|
|
641
|
+
}),
|
|
642
|
+
start_time: z.string().openapi({
|
|
643
|
+
description: 'Start time of the booking',
|
|
644
|
+
example: '08:00'
|
|
645
|
+
}),
|
|
646
|
+
end_time: z.string().openapi({
|
|
647
|
+
description: 'End time of the booking',
|
|
648
|
+
example: '08:30'
|
|
649
|
+
}),
|
|
650
|
+
company_role: z.string().nullable().openapi({
|
|
651
|
+
description: 'Company role for the booking',
|
|
652
|
+
example: 'exhibitor'
|
|
653
|
+
}),
|
|
654
|
+
company: companyDetailsSchema.openapi({
|
|
655
|
+
description: 'Company details'
|
|
656
|
+
}),
|
|
657
|
+
vehicle: vehicleDetailsSchema.openapi({
|
|
658
|
+
description: 'Vehicle details'
|
|
659
|
+
}),
|
|
660
|
+
event_id: z.number().openapi({
|
|
661
|
+
description: 'ID of the event',
|
|
662
|
+
example: 1
|
|
663
|
+
}),
|
|
664
|
+
event_name: z.string().openapi({
|
|
665
|
+
description: 'Name of the event',
|
|
666
|
+
example: 'Paris Fashion Week 2025'
|
|
667
|
+
}),
|
|
668
|
+
event_code: z.string().openapi({
|
|
669
|
+
description: 'Code of the event',
|
|
670
|
+
example: 'PFW2025'
|
|
671
|
+
}),
|
|
672
|
+
venue_id: z.number().nullable().openapi({
|
|
673
|
+
description: 'ID of the venue',
|
|
674
|
+
example: 1
|
|
675
|
+
}),
|
|
676
|
+
venue_name: z.string().nullable().openapi({
|
|
677
|
+
description: 'Name of the venue',
|
|
678
|
+
example: 'Paris Expo Porte de Versailles'
|
|
679
|
+
}),
|
|
680
|
+
request_type: z.string().openapi({
|
|
681
|
+
description: 'Type of parking area schedule (assembly/dismantling)',
|
|
682
|
+
example: 'assembly'
|
|
683
|
+
}),
|
|
684
|
+
duration: z.number().openapi({
|
|
685
|
+
description: 'Duration of the booking in minutes',
|
|
686
|
+
example: 30
|
|
687
|
+
}),
|
|
688
|
+
parking_area_schedule_id: z.number().openapi({
|
|
689
|
+
description: 'ID of the parking area schedule',
|
|
690
|
+
example: 456
|
|
691
|
+
}),
|
|
692
|
+
banner: documentSchema.nullable().openapi({
|
|
693
|
+
description: 'Event banner document',
|
|
694
|
+
example: {
|
|
695
|
+
url: 'https://example.com/event-banner.jpg',
|
|
696
|
+
name: 'event-banner.jpg',
|
|
697
|
+
type: 'image/jpeg'
|
|
698
|
+
}
|
|
699
|
+
}),
|
|
700
|
+
created_at: z.string().openapi({
|
|
701
|
+
description: 'Timestamp when booking was created',
|
|
702
|
+
example: '2025-12-05T10:30:00.000Z'
|
|
703
|
+
}),
|
|
704
|
+
updated_at: z.string().openapi({
|
|
705
|
+
description: 'Timestamp when booking was last updated',
|
|
706
|
+
example: '2025-12-05T10:30:00.000Z'
|
|
707
|
+
})
|
|
708
|
+
})
|
|
709
|
+
.openapi('ParkingBookingDetailsData');
|
|
710
|
+
export const getParkingBookingDetailsResponseSchema = createSuccessResponseSchema(parkingBookingDetailsDataSchema, 'GetParkingBookingDetailsResponse', 'Booking details with access pass information');
|
|
711
|
+
// ------------------------------
|
|
712
|
+
// Get booking details by token schemas
|
|
713
|
+
// ------------------------------
|
|
714
|
+
export const getParkingBookingDetailsByTokenBodySchema = z
|
|
715
|
+
.object({
|
|
716
|
+
access_token: z.string().min(1, 'Access token is required').openapi({
|
|
717
|
+
description: 'Access pass token from confirmed booking',
|
|
718
|
+
example: 'ACCESS_1a2b3c4d5e6f7g8h_eyJib29raW5nSWQiOjEyM30%3D'
|
|
719
|
+
})
|
|
720
|
+
})
|
|
721
|
+
.openapi('GetParkingBookingDetailsByTokenBody');
|
|
722
|
+
export const getParkingBookingDetailsByTokenResponseSchema = createSuccessResponseSchema(bookingDetailsDataSchema, 'GetParkingBookingDetailsByTokenResponse', 'Booking details retrieved by access token');
|
|
723
|
+
// ------------------------------
|
|
724
|
+
// Get booking details by QR schemas
|
|
725
|
+
// ------------------------------
|
|
726
|
+
export const getParkingBookingDetailsByQrBodySchema = z
|
|
727
|
+
.object({
|
|
728
|
+
qr_token: z.string().min(1, 'QR token is required').openapi({
|
|
729
|
+
description: 'QR token from confirmed booking',
|
|
730
|
+
example: 'ACCESS_1a2b3c4d5e6f7g8h_eyJib29raW5nSWQiOjEyM30%3D'
|
|
731
|
+
})
|
|
732
|
+
})
|
|
733
|
+
.openapi('GetBookingDetailsByQrBody');
|
|
734
|
+
export const getParkingBookingDetailsByQrResponseSchema = createSuccessResponseSchema(bookingDetailsDataSchema, 'GetBookingDetailsByQrResponse', 'Booking details retrieved by QR token');
|