@venulog/phasing-engine-schemas 0.2.0-alpha.0 → 0.2.0-alpha.2
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/phaseSlotScheduleType.d.ts +4 -0
- package/dist/enums/phaseSlotScheduleType.js +5 -0
- package/dist/event.d.ts +18 -0
- package/dist/event.js +40 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/phaseBooking.d.ts +224 -358
- package/dist/phaseBooking.js +318 -452
- package/dist/phaseSlot.d.ts +60 -57
- package/dist/phaseSlot.js +187 -55
- package/package.json +5 -1
- package/dist/enums/slotStatus.d.ts +0 -5
- package/dist/enums/slotStatus.js +0 -6
package/dist/phaseBooking.js
CHANGED
|
@@ -3,7 +3,7 @@ import { paginationSchema } from './pagination.js';
|
|
|
3
3
|
import { BookingStatus } from './enums/bookingStatus.js';
|
|
4
4
|
import { createSuccessResponseSchema, createMessageDataResponseSchema } from './common.js';
|
|
5
5
|
import { z } from './zod.js';
|
|
6
|
-
import {
|
|
6
|
+
import { PhaseSlotScheduleType } from './enums/phaseSlotScheduleType.js';
|
|
7
7
|
// ------------------------------
|
|
8
8
|
// Query parameters schema
|
|
9
9
|
// ------------------------------
|
|
@@ -25,22 +25,6 @@ export const getEventBookingsQuerySchema = z
|
|
|
25
25
|
})
|
|
26
26
|
.extend(paginationSchema.shape)
|
|
27
27
|
.openapi('GetEventBookingsQuery');
|
|
28
|
-
// ------------------------------
|
|
29
|
-
// Path parameters schema
|
|
30
|
-
// ------------------------------
|
|
31
|
-
export const cancelPhaseSlotParamsSchema = z
|
|
32
|
-
.object({
|
|
33
|
-
slotId: z
|
|
34
|
-
.string()
|
|
35
|
-
.min(1, 'Slot ID is required')
|
|
36
|
-
.transform(val => parseInt(val, 10))
|
|
37
|
-
.refine(val => !isNaN(val) && val > 0, { message: 'Slot ID must be positive' })
|
|
38
|
-
.openapi({
|
|
39
|
-
description: 'The ID of the phase slot to cancel',
|
|
40
|
-
example: '1'
|
|
41
|
-
})
|
|
42
|
-
})
|
|
43
|
-
.openapi('CancelPhaseSlotParams');
|
|
44
28
|
export const closeEventParamsSchema = z
|
|
45
29
|
.object({
|
|
46
30
|
eventId: z
|
|
@@ -54,17 +38,6 @@ export const closeEventParamsSchema = z
|
|
|
54
38
|
})
|
|
55
39
|
})
|
|
56
40
|
.openapi('CloseEventParams');
|
|
57
|
-
// ------------------------------
|
|
58
|
-
// Request body schemas
|
|
59
|
-
// ------------------------------
|
|
60
|
-
export const cancelPhaseSlotBodySchema = z
|
|
61
|
-
.object({
|
|
62
|
-
reason: z.string().optional().openapi({
|
|
63
|
-
description: 'Optional reason for cancellation (for audit purposes)',
|
|
64
|
-
example: 'Event postponed'
|
|
65
|
-
})
|
|
66
|
-
})
|
|
67
|
-
.openapi('CancelPhaseSlotBody');
|
|
68
41
|
export const closeEventBodySchema = z
|
|
69
42
|
.object({
|
|
70
43
|
reason: z.string().optional().openapi({
|
|
@@ -80,20 +53,57 @@ export const vehicleTypeSchema = z.object({
|
|
|
80
53
|
id: z.number(),
|
|
81
54
|
name: z.string()
|
|
82
55
|
});
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
56
|
+
// New unified phase slot schedule schema (from database response)
|
|
57
|
+
export const phaseSlotScheduleSchema = z
|
|
58
|
+
.object({
|
|
59
|
+
id: z.number().int().positive().openapi({
|
|
60
|
+
description: 'Unique identifier for the schedule',
|
|
61
|
+
example: 1
|
|
62
|
+
}),
|
|
63
|
+
date: z.string().openapi({
|
|
64
|
+
description: 'Date of the schedule (YYYY-MM-DD format)',
|
|
65
|
+
example: '2025-12-15'
|
|
66
|
+
}),
|
|
67
|
+
start_time: z.string().openapi({
|
|
68
|
+
description: 'Start time (HH:MM format)',
|
|
69
|
+
example: '06:00'
|
|
70
|
+
}),
|
|
71
|
+
end_time: z.string().openapi({
|
|
72
|
+
description: 'End time (HH:MM format)',
|
|
73
|
+
example: '09:00'
|
|
74
|
+
}),
|
|
75
|
+
duration: z.number().openapi({
|
|
76
|
+
description: 'Duration in minutes',
|
|
77
|
+
example: 180
|
|
78
|
+
}),
|
|
79
|
+
phase_slot_id: z.number().int().positive().openapi({
|
|
80
|
+
description: 'ID of the associated phase slot',
|
|
81
|
+
example: 101
|
|
82
|
+
}),
|
|
83
|
+
phase_slot_schedule_type: z
|
|
84
|
+
.enum([PhaseSlotScheduleType.ASSEMBLY, PhaseSlotScheduleType.DISMANTLING])
|
|
85
|
+
.openapi({
|
|
86
|
+
description: 'Type of schedule',
|
|
87
|
+
example: PhaseSlotScheduleType.ASSEMBLY
|
|
88
|
+
}),
|
|
89
|
+
created_at: z.string().openapi({
|
|
90
|
+
description: 'Timestamp when schedule was created',
|
|
91
|
+
example: '2025-12-09T10:00:00.000Z'
|
|
92
|
+
}),
|
|
93
|
+
updated_at: z.string().openapi({
|
|
94
|
+
description: 'Timestamp when schedule was updated',
|
|
95
|
+
example: '2025-12-09T10:30:00.000Z'
|
|
96
|
+
}),
|
|
97
|
+
created_by: z.uuid().nullable().openapi({
|
|
98
|
+
description: 'UUID of user who created the schedule',
|
|
99
|
+
example: '550e8400-e29b-41d4-a716-446655440000'
|
|
100
|
+
}),
|
|
101
|
+
updated_by: z.uuid().nullable().openapi({
|
|
102
|
+
description: 'UUID of user who last updated the schedule',
|
|
103
|
+
example: '550e8400-e29b-41d4-a716-446655440000'
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
.openapi('PhaseSlotSchedule');
|
|
97
107
|
export const companySchema = z.object({
|
|
98
108
|
id: z.number(),
|
|
99
109
|
company_name: z.string(),
|
|
@@ -119,38 +129,127 @@ export const companySchema = z.object({
|
|
|
119
129
|
});
|
|
120
130
|
export const phaseBookingSchema = z.object({
|
|
121
131
|
id: z.number(),
|
|
122
|
-
|
|
123
|
-
phase_slot_id: z.number(),
|
|
132
|
+
phase_slot_schedule_id: z.number(),
|
|
124
133
|
status: z.enum(BookingStatus),
|
|
125
134
|
is_active: z.boolean(),
|
|
126
135
|
created_at: z.string(),
|
|
127
136
|
updated_at: z.string(),
|
|
128
137
|
created_by: z.string().nullable(),
|
|
129
138
|
updated_by: z.string().nullable(),
|
|
130
|
-
|
|
131
|
-
|
|
139
|
+
vehicle: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
140
|
+
company: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
141
|
+
booking_date: z.string().nullable().optional(),
|
|
142
|
+
start_time: z.string().nullable().optional(),
|
|
143
|
+
end_time: z.string().nullable().optional()
|
|
132
144
|
});
|
|
145
|
+
export const companyDetailsSchema = z
|
|
146
|
+
.object({
|
|
147
|
+
company_role: z.string().min(1, 'Company role is required').openapi({
|
|
148
|
+
description: 'Company role',
|
|
149
|
+
example: 'exhibitor'
|
|
150
|
+
}),
|
|
151
|
+
hall: z.string().min(1, 'Hall is required').openapi({
|
|
152
|
+
description: 'Hall location',
|
|
153
|
+
example: 'Hall 1'
|
|
154
|
+
}),
|
|
155
|
+
stand_number: z.string().min(1, 'Stand number is required').openapi({
|
|
156
|
+
description: 'Stand number',
|
|
157
|
+
example: 'A-123'
|
|
158
|
+
}),
|
|
159
|
+
company_name: z.string().min(1, 'Company name is required').openapi({
|
|
160
|
+
description: 'Company name',
|
|
161
|
+
example: 'Acme Corp'
|
|
162
|
+
}),
|
|
163
|
+
business: z.string().min(1, 'Business is required').openapi({
|
|
164
|
+
description: 'Type of business',
|
|
165
|
+
example: 'Technology'
|
|
166
|
+
}),
|
|
167
|
+
departure_city: z.string().min(1, 'Departure city is required').openapi({
|
|
168
|
+
description: 'City of departure',
|
|
169
|
+
example: 'Paris'
|
|
170
|
+
}),
|
|
171
|
+
contact_name: z.string().min(1, 'Contact name is required').openapi({
|
|
172
|
+
description: 'Contact person name',
|
|
173
|
+
example: 'John Doe'
|
|
174
|
+
}),
|
|
175
|
+
email: z.email('Valid email is required').openapi({
|
|
176
|
+
description: 'Contact email',
|
|
177
|
+
example: 'john.doe@acme.com'
|
|
178
|
+
}),
|
|
179
|
+
phone: z.string().min(1, 'Phone is required').openapi({
|
|
180
|
+
description: 'Contact phone number',
|
|
181
|
+
example: '+33 1 23 45 67 89'
|
|
182
|
+
}),
|
|
183
|
+
driver_name: z.string().min(1, 'Driver name is required').openapi({
|
|
184
|
+
description: 'Driver name',
|
|
185
|
+
example: 'Jean Martin'
|
|
186
|
+
}),
|
|
187
|
+
driver_phone: z.string().min(1, 'Driver phone is required').openapi({
|
|
188
|
+
description: 'Driver phone number',
|
|
189
|
+
example: '+33 6 12 34 56 78'
|
|
190
|
+
}),
|
|
191
|
+
transport_company: z.string().min(1, 'Transport company is required').openapi({
|
|
192
|
+
description: 'Transport company name',
|
|
193
|
+
example: 'Fast Transport Ltd'
|
|
194
|
+
})
|
|
195
|
+
})
|
|
196
|
+
.openapi('CompanyDetails');
|
|
197
|
+
export const vehicleDetailsSchema = z
|
|
198
|
+
.object({
|
|
199
|
+
vehicle_type: z.string().min(1, 'Vehicle type is required').openapi({
|
|
200
|
+
description: 'Type of vehicle',
|
|
201
|
+
example: 'Truck'
|
|
202
|
+
}),
|
|
203
|
+
unloading_method: z.string().min(1, 'Unloading method is required').openapi({
|
|
204
|
+
description: 'Method of unloading',
|
|
205
|
+
example: 'Manual'
|
|
206
|
+
}),
|
|
207
|
+
license_plate: z.string().min(1, 'License plate is required').openapi({
|
|
208
|
+
description: 'Vehicle license plate',
|
|
209
|
+
example: 'AB-123-CD'
|
|
210
|
+
}),
|
|
211
|
+
trailer_registration: z.string().optional().openapi({
|
|
212
|
+
description: 'Trailer registration number',
|
|
213
|
+
example: 'TR-456-EF'
|
|
214
|
+
})
|
|
215
|
+
})
|
|
216
|
+
.openapi('VehicleDetails');
|
|
133
217
|
export const createBookingBodySchema = z
|
|
134
218
|
.object({
|
|
135
|
-
|
|
219
|
+
// Event & Basic Info
|
|
220
|
+
event_id: z
|
|
136
221
|
.number()
|
|
137
222
|
.int()
|
|
138
223
|
.positive({
|
|
139
|
-
message: '
|
|
224
|
+
message: 'Event ID must be a positive integer'
|
|
140
225
|
})
|
|
141
226
|
.openapi({
|
|
142
|
-
description: 'ID of the
|
|
143
|
-
example:
|
|
227
|
+
description: 'ID of the event to create the booking for',
|
|
228
|
+
example: 1
|
|
144
229
|
}),
|
|
145
|
-
|
|
146
|
-
.
|
|
147
|
-
.
|
|
148
|
-
.positive({
|
|
149
|
-
message: 'Phase slot ID must be a positive integer'
|
|
150
|
-
})
|
|
230
|
+
request_type: z
|
|
231
|
+
.enum([PhaseSlotScheduleType.ASSEMBLY, PhaseSlotScheduleType.DISMANTLING])
|
|
232
|
+
.default(PhaseSlotScheduleType.ASSEMBLY)
|
|
151
233
|
.openapi({
|
|
152
|
-
description: '
|
|
153
|
-
example:
|
|
234
|
+
description: 'Type of request (assembly or dismantling)',
|
|
235
|
+
example: PhaseSlotScheduleType.ASSEMBLY
|
|
236
|
+
}),
|
|
237
|
+
// Time slot selection
|
|
238
|
+
selected_date: z.string().min(1, 'Date is required').openapi({
|
|
239
|
+
description: 'Selected date (YYYY-MM-DD)',
|
|
240
|
+
example: '2025-12-15'
|
|
241
|
+
}),
|
|
242
|
+
selected_time: z.string().min(1, 'Time is required').openapi({
|
|
243
|
+
description: 'Selected time slot (HH:MM)',
|
|
244
|
+
example: '08:00'
|
|
245
|
+
}),
|
|
246
|
+
// Company details
|
|
247
|
+
company: companyDetailsSchema.openapi({
|
|
248
|
+
description: 'Company details including stand, contact, and driver info'
|
|
249
|
+
}),
|
|
250
|
+
// Vehicle details
|
|
251
|
+
vehicle: vehicleDetailsSchema.openapi({
|
|
252
|
+
description: 'Vehicle details'
|
|
154
253
|
})
|
|
155
254
|
})
|
|
156
255
|
.openapi('CreateBookingBody');
|
|
@@ -160,22 +259,32 @@ export const createBookingDataSchema = z
|
|
|
160
259
|
description: 'ID of the created booking',
|
|
161
260
|
example: 789
|
|
162
261
|
}),
|
|
163
|
-
|
|
164
|
-
description: 'ID of the
|
|
165
|
-
example: 123
|
|
166
|
-
}),
|
|
167
|
-
phase_slot_id: z.number().openapi({
|
|
168
|
-
description: 'ID of the booked phase slot',
|
|
262
|
+
phase_slot_schedule_id: z.number().openapi({
|
|
263
|
+
description: 'ID of the phase slot schedule',
|
|
169
264
|
example: 456
|
|
170
265
|
}),
|
|
171
|
-
slot_number: z.number().openapi({
|
|
172
|
-
description: 'Slot number',
|
|
173
|
-
example: 42
|
|
174
|
-
}),
|
|
175
266
|
status: z.enum(BookingStatus).openapi({
|
|
176
267
|
description: 'Booking status',
|
|
177
268
|
example: BookingStatus.BOOKED
|
|
178
269
|
}),
|
|
270
|
+
booking_date: z.string().openapi({
|
|
271
|
+
description: 'Booking date',
|
|
272
|
+
example: '2025-12-15'
|
|
273
|
+
}),
|
|
274
|
+
start_time: z.string().openapi({
|
|
275
|
+
description: 'Start time',
|
|
276
|
+
example: '08:00'
|
|
277
|
+
}),
|
|
278
|
+
end_time: z.string().openapi({
|
|
279
|
+
description: 'End time',
|
|
280
|
+
example: '08:30'
|
|
281
|
+
}),
|
|
282
|
+
company: companyDetailsSchema.openapi({
|
|
283
|
+
description: 'Company details including stand, contact, and driver info'
|
|
284
|
+
}),
|
|
285
|
+
vehicle: vehicleDetailsSchema.openapi({
|
|
286
|
+
description: 'Vehicle details'
|
|
287
|
+
}),
|
|
179
288
|
created_at: z.string().openapi({
|
|
180
289
|
description: 'Timestamp when booking was created',
|
|
181
290
|
example: '2025-12-05T10:30:00.000Z'
|
|
@@ -197,31 +306,6 @@ export const eventBookingsDataSchema = z
|
|
|
197
306
|
})
|
|
198
307
|
.openapi('EventBookingsData');
|
|
199
308
|
export const eventBookingsResponseSchema = createSuccessResponseSchema(eventBookingsDataSchema, 'EventBookingsResponse', 'Event bookings data with phase slot details');
|
|
200
|
-
export const cancelPhaseSlotDataSchema = z
|
|
201
|
-
.object({
|
|
202
|
-
slot_id: z.number().openapi({
|
|
203
|
-
description: 'ID of the cancelled slot',
|
|
204
|
-
example: 1
|
|
205
|
-
}),
|
|
206
|
-
status: z.enum(SlotStatus).openapi({
|
|
207
|
-
description: 'New status of the slot',
|
|
208
|
-
example: SlotStatus.AVAILABLE
|
|
209
|
-
}),
|
|
210
|
-
cancelled_at: z.string().openapi({
|
|
211
|
-
description: 'Timestamp when the slot was cancelled',
|
|
212
|
-
example: '2025-12-03T20:47:00.000Z'
|
|
213
|
-
}),
|
|
214
|
-
cancelled_by: z.string().nullable().openapi({
|
|
215
|
-
description: 'ID of the user who cancelled the slot',
|
|
216
|
-
example: null
|
|
217
|
-
}),
|
|
218
|
-
reason: z.string().nullable().openapi({
|
|
219
|
-
description: 'Reason for cancellation',
|
|
220
|
-
example: 'Event postponed'
|
|
221
|
-
})
|
|
222
|
-
})
|
|
223
|
-
.openapi('CancelPhaseSlotData');
|
|
224
|
-
export const cancelPhaseSlotResponseSchema = createMessageDataResponseSchema(cancelPhaseSlotDataSchema, 'CancelPhaseSlotResponse', 'Phase slot cancelled successfully', 'Details of the cancelled phase slot');
|
|
225
309
|
export const closeEventDataSchema = z
|
|
226
310
|
.object({
|
|
227
311
|
event_id: z.number().openapi({
|
|
@@ -268,7 +352,6 @@ export const confirmBookingResponseSchema = z.object({
|
|
|
268
352
|
booking_id: z.number(),
|
|
269
353
|
booking_status: z.enum(BookingStatus),
|
|
270
354
|
slot_id: z.number(),
|
|
271
|
-
slot_status: z.enum(SlotStatus),
|
|
272
355
|
confirmed_at: z.string(),
|
|
273
356
|
confirmed_by: z.string().nullable()
|
|
274
357
|
})
|
|
@@ -302,10 +385,6 @@ export const refuseBookingDataSchema = z
|
|
|
302
385
|
description: 'ID of the associated phase slot',
|
|
303
386
|
example: 10
|
|
304
387
|
}),
|
|
305
|
-
slot_status: z.enum([SlotStatus.AVAILABLE]).openapi({
|
|
306
|
-
description: 'New status of the phase slot',
|
|
307
|
-
example: SlotStatus.AVAILABLE
|
|
308
|
-
}),
|
|
309
388
|
refused_at: z.string().openapi({
|
|
310
389
|
description: 'ISO 8601 timestamp when the booking was refused',
|
|
311
390
|
example: '2025-12-08T10:30:00.000Z'
|
|
@@ -335,44 +414,15 @@ export const createPhaseSlotsBodySchema = z
|
|
|
335
414
|
}),
|
|
336
415
|
slots: z
|
|
337
416
|
.array(z.object({
|
|
338
|
-
slot_number: z
|
|
339
|
-
.number()
|
|
340
|
-
.int()
|
|
341
|
-
.positive({
|
|
342
|
-
message: 'Slot number must be a positive integer'
|
|
343
|
-
})
|
|
344
|
-
.openapi({
|
|
345
|
-
description: 'Unique slot number within the event',
|
|
346
|
-
example: 42
|
|
347
|
-
}),
|
|
348
|
-
vehicle_type_id: z
|
|
349
|
-
.number()
|
|
350
|
-
.int()
|
|
351
|
-
.positive({
|
|
352
|
-
message: 'Vehicle type ID must be a positive integer'
|
|
353
|
-
})
|
|
354
|
-
.nullable()
|
|
355
|
-
.optional()
|
|
356
|
-
.openapi({
|
|
357
|
-
description: 'Optional vehicle type ID for the slot',
|
|
358
|
-
example: 1
|
|
359
|
-
}),
|
|
360
417
|
company_role: z.string().min(1).nullable().optional().openapi({
|
|
361
418
|
description: 'Optional company role for the slot',
|
|
362
419
|
example: 'buyer'
|
|
363
|
-
}),
|
|
364
|
-
status: z.enum(SlotStatus).optional().openapi({
|
|
365
|
-
description: 'Initial status of the slot (defaults to available)',
|
|
366
|
-
example: SlotStatus.AVAILABLE
|
|
367
420
|
})
|
|
368
421
|
}))
|
|
369
422
|
.min(1, 'At least one slot must be provided')
|
|
370
423
|
.openapi({
|
|
371
424
|
description: 'Array of slots to create',
|
|
372
|
-
example: [
|
|
373
|
-
{ slot_number: 42, vehicle_type_id: 1, company_role: 'buyer' },
|
|
374
|
-
{ slot_number: 43, vehicle_type_id: 2, company_role: 'seller' }
|
|
375
|
-
]
|
|
425
|
+
example: [{ company_role: 'buyer' }, { company_role: 'seller' }]
|
|
376
426
|
})
|
|
377
427
|
})
|
|
378
428
|
.openapi('CreatePhaseSlotsBody');
|
|
@@ -386,22 +436,10 @@ export const createPhaseSlotDataSchema = z
|
|
|
386
436
|
description: 'ID of the event',
|
|
387
437
|
example: 1
|
|
388
438
|
}),
|
|
389
|
-
slot_number: z.number().openapi({
|
|
390
|
-
description: 'Slot number',
|
|
391
|
-
example: 42
|
|
392
|
-
}),
|
|
393
|
-
vehicle_type_id: z.number().nullable().openapi({
|
|
394
|
-
description: 'Vehicle type ID',
|
|
395
|
-
example: 1
|
|
396
|
-
}),
|
|
397
439
|
company_role: z.string().nullable().openapi({
|
|
398
440
|
description: 'Company role',
|
|
399
441
|
example: 'buyer'
|
|
400
442
|
}),
|
|
401
|
-
status: z.enum(SlotStatus).openapi({
|
|
402
|
-
description: 'Slot status',
|
|
403
|
-
example: SlotStatus.AVAILABLE
|
|
404
|
-
}),
|
|
405
443
|
is_active: z.boolean().openapi({
|
|
406
444
|
description: 'Whether the slot is active',
|
|
407
445
|
example: true,
|
|
@@ -433,13 +471,13 @@ export const createPhaseSlotsDataSchema = z
|
|
|
433
471
|
}),
|
|
434
472
|
failed_slots: z
|
|
435
473
|
.array(z.object({
|
|
436
|
-
|
|
437
|
-
description: '
|
|
438
|
-
example:
|
|
474
|
+
index: z.number().openapi({
|
|
475
|
+
description: 'Index of the slot in the request that failed to create',
|
|
476
|
+
example: 0
|
|
439
477
|
}),
|
|
440
478
|
error: z.string().openapi({
|
|
441
479
|
description: 'Error message explaining why the slot creation failed',
|
|
442
|
-
example: '
|
|
480
|
+
example: 'Failed to create slot'
|
|
443
481
|
})
|
|
444
482
|
}))
|
|
445
483
|
.openapi({
|
|
@@ -467,36 +505,9 @@ export const updatePhaseSlotParamsSchema = z
|
|
|
467
505
|
.openapi('UpdatePhaseSlotParams');
|
|
468
506
|
export const updatePhaseSlotBodySchema = z
|
|
469
507
|
.object({
|
|
470
|
-
slot_number: z
|
|
471
|
-
.number()
|
|
472
|
-
.int()
|
|
473
|
-
.positive({
|
|
474
|
-
message: 'Slot number must be a positive integer'
|
|
475
|
-
})
|
|
476
|
-
.optional()
|
|
477
|
-
.openapi({
|
|
478
|
-
description: 'New slot number (must be unique within the event)',
|
|
479
|
-
example: 43
|
|
480
|
-
}),
|
|
481
|
-
vehicle_type_id: z
|
|
482
|
-
.number()
|
|
483
|
-
.int()
|
|
484
|
-
.positive({
|
|
485
|
-
message: 'Vehicle type ID must be a positive integer'
|
|
486
|
-
})
|
|
487
|
-
.nullable()
|
|
488
|
-
.optional()
|
|
489
|
-
.openapi({
|
|
490
|
-
description: 'New vehicle type ID for the slot',
|
|
491
|
-
example: 2
|
|
492
|
-
}),
|
|
493
508
|
company_role: z.string().min(1).nullable().optional().openapi({
|
|
494
509
|
description: 'New company role for the slot',
|
|
495
510
|
example: 'seller'
|
|
496
|
-
}),
|
|
497
|
-
status: z.enum(SlotStatus).optional().openapi({
|
|
498
|
-
description: 'New status for the slot',
|
|
499
|
-
example: SlotStatus.RESERVED
|
|
500
511
|
})
|
|
501
512
|
})
|
|
502
513
|
.refine(data => Object.keys(data).length > 0, {
|
|
@@ -513,22 +524,10 @@ export const updatePhaseSlotDataSchema = z
|
|
|
513
524
|
description: 'ID of the event',
|
|
514
525
|
example: 1
|
|
515
526
|
}),
|
|
516
|
-
slot_number: z.number().openapi({
|
|
517
|
-
description: 'Updated slot number',
|
|
518
|
-
example: 43
|
|
519
|
-
}),
|
|
520
|
-
vehicle_type_id: z.number().nullable().openapi({
|
|
521
|
-
description: 'Updated vehicle type ID',
|
|
522
|
-
example: 2
|
|
523
|
-
}),
|
|
524
527
|
company_role: z.string().nullable().openapi({
|
|
525
528
|
description: 'Updated company role',
|
|
526
529
|
example: 'seller'
|
|
527
530
|
}),
|
|
528
|
-
status: z.enum(SlotStatus).openapi({
|
|
529
|
-
description: 'Updated slot status',
|
|
530
|
-
example: SlotStatus.RESERVED
|
|
531
|
-
}),
|
|
532
531
|
is_active: z.boolean().openapi({
|
|
533
532
|
description: 'Whether the slot is active',
|
|
534
533
|
example: true
|
|
@@ -545,163 +544,29 @@ export const updatePhaseSlotDataSchema = z
|
|
|
545
544
|
.openapi('UpdatePhaseSlotData');
|
|
546
545
|
export const updatePhaseSlotResponseSchema = createMessageDataResponseSchema(updatePhaseSlotDataSchema, 'UpdatePhaseSlotResponse', 'Phase slot updated successfully', 'Details of the updated phase slot');
|
|
547
546
|
// ------------------------------
|
|
548
|
-
// Phase Slot
|
|
547
|
+
// Phase Slot Schedules Schemas
|
|
549
548
|
// ------------------------------
|
|
550
|
-
export const
|
|
551
|
-
.object({
|
|
552
|
-
id: z.number().int().positive().openapi({
|
|
553
|
-
description: 'Unique identifier for the assembly',
|
|
554
|
-
example: 1
|
|
555
|
-
}),
|
|
556
|
-
date: z.string().openapi({
|
|
557
|
-
description: 'Date of the assembly (YYYY-MM-DD format)',
|
|
558
|
-
example: '2025-12-15'
|
|
559
|
-
}),
|
|
560
|
-
start_time: z.string().openapi({
|
|
561
|
-
description: 'Start time of the assembly (HH:MM format)',
|
|
562
|
-
example: '06:00'
|
|
563
|
-
}),
|
|
564
|
-
end_time: z.string().openapi({
|
|
565
|
-
description: 'End time of the assembly (HH:MM format)',
|
|
566
|
-
example: '09:00'
|
|
567
|
-
}),
|
|
568
|
-
duration: z.number().openapi({
|
|
569
|
-
description: 'Duration of the assembly in minutes',
|
|
570
|
-
example: 180
|
|
571
|
-
}),
|
|
572
|
-
phase_slot_id: z.number().int().positive().openapi({
|
|
573
|
-
description: 'ID of the associated phase slot',
|
|
574
|
-
example: 101
|
|
575
|
-
}),
|
|
576
|
-
created_at: z.string().openapi({
|
|
577
|
-
description: 'Timestamp when assembly was created',
|
|
578
|
-
example: '2025-12-09T10:00:00.000Z'
|
|
579
|
-
}),
|
|
580
|
-
updated_at: z.string().openapi({
|
|
581
|
-
description: 'Timestamp when assembly was updated',
|
|
582
|
-
example: '2025-12-09T10:30:00.000Z'
|
|
583
|
-
})
|
|
584
|
-
})
|
|
585
|
-
.openapi('PhaseSlotAssembly');
|
|
586
|
-
export const phaseSlotDismantlingSchema = z
|
|
549
|
+
export const upsertPhaseSlotScheduleItemSchema = z
|
|
587
550
|
.object({
|
|
588
|
-
id: z.number().int().positive().openapi({
|
|
589
|
-
description: 'Unique identifier for
|
|
551
|
+
id: z.number().int().positive().optional().openapi({
|
|
552
|
+
description: 'Unique identifier for existing schedule (required for updates)',
|
|
590
553
|
example: 1
|
|
591
554
|
}),
|
|
592
|
-
date: z.string().openapi({
|
|
593
|
-
description: 'Date of the dismantling (YYYY-MM-DD format)',
|
|
594
|
-
example: '2025-12-15'
|
|
595
|
-
}),
|
|
596
|
-
start_time: z.string().openapi({
|
|
597
|
-
description: 'Start time of the dismantling (HH:MM format)',
|
|
598
|
-
example: '06:00'
|
|
599
|
-
}),
|
|
600
|
-
end_time: z.string().openapi({
|
|
601
|
-
description: 'End time of the dismantling (HH:MM format)',
|
|
602
|
-
example: '09:00'
|
|
603
|
-
}),
|
|
604
|
-
duration: z.number().openapi({
|
|
605
|
-
description: 'Duration of the dismantling in minutes',
|
|
606
|
-
example: 180
|
|
607
|
-
}),
|
|
608
555
|
phase_slot_id: z.number().int().positive().openapi({
|
|
609
556
|
description: 'ID of the associated phase slot',
|
|
610
557
|
example: 101
|
|
611
558
|
}),
|
|
612
|
-
created_at: z.string().openapi({
|
|
613
|
-
description: 'Timestamp when dismantling was created',
|
|
614
|
-
example: '2025-12-09T10:00:00.000Z'
|
|
615
|
-
}),
|
|
616
|
-
updated_at: z.string().openapi({
|
|
617
|
-
description: 'Timestamp when dismantling was updated',
|
|
618
|
-
example: '2025-12-09T10:30:00.000Z'
|
|
619
|
-
})
|
|
620
|
-
})
|
|
621
|
-
.openapi('PhaseSlotDismantling');
|
|
622
|
-
export const upsertPhaseSlotAssemblySchema = z
|
|
623
|
-
.object({
|
|
624
|
-
date: z
|
|
625
|
-
.string()
|
|
626
|
-
.regex(/^\d{4}-\d{2}-\d{2}$/, 'Date must be in YYYY-MM-DD format')
|
|
627
|
-
.openapi({
|
|
628
|
-
description: 'Date of the assembly (YYYY-MM-DD format)',
|
|
629
|
-
example: '2025-12-15'
|
|
630
|
-
}),
|
|
631
|
-
start_time: z
|
|
632
|
-
.string()
|
|
633
|
-
.regex(/^\d{2}:\d{2}$/, 'Time must be in HH:MM format')
|
|
634
|
-
.optional()
|
|
635
|
-
.openapi({
|
|
636
|
-
description: 'Start time of the assembly (HH:MM format). Defaults to 06:00',
|
|
637
|
-
example: '06:00'
|
|
638
|
-
}),
|
|
639
|
-
end_time: z
|
|
640
|
-
.string()
|
|
641
|
-
.regex(/^\d{2}:\d{2}$/, 'Time must be in HH:MM format')
|
|
642
|
-
.optional()
|
|
643
|
-
.openapi({
|
|
644
|
-
description: 'End time of the assembly (HH:MM format). Defaults to 09:00',
|
|
645
|
-
example: '09:00'
|
|
646
|
-
}),
|
|
647
|
-
duration: z.number().positive().optional().openapi({
|
|
648
|
-
description: 'Duration of the assembly in minutes. Defaults to 60',
|
|
649
|
-
example: 180
|
|
650
|
-
}),
|
|
651
|
-
phase_slot_id: z.number().int().positive().openapi({
|
|
652
|
-
description: 'ID of the associated phase slot',
|
|
653
|
-
example: 101
|
|
654
|
-
})
|
|
655
|
-
})
|
|
656
|
-
.openapi('UpsertPhaseSlotAssembly');
|
|
657
|
-
export const upsertPhaseSlotDismantlingSchema = z
|
|
658
|
-
.object({
|
|
659
559
|
date: z
|
|
660
560
|
.string()
|
|
661
561
|
.regex(/^\d{4}-\d{2}-\d{2}$/, 'Date must be in YYYY-MM-DD format')
|
|
662
562
|
.openapi({
|
|
663
|
-
description: 'Date of the
|
|
563
|
+
description: 'Date of the schedule (YYYY-MM-DD format)',
|
|
664
564
|
example: '2025-12-15'
|
|
665
565
|
}),
|
|
666
566
|
start_time: z
|
|
667
567
|
.string()
|
|
668
568
|
.regex(/^\d{2}:\d{2}$/, 'Time must be in HH:MM format')
|
|
669
|
-
.
|
|
670
|
-
.openapi({
|
|
671
|
-
description: 'Start time of the dismantling (HH:MM format). Defaults to 06:00',
|
|
672
|
-
example: '06:00'
|
|
673
|
-
}),
|
|
674
|
-
end_time: z
|
|
675
|
-
.string()
|
|
676
|
-
.regex(/^\d{2}:\d{2}$/, 'Time must be in HH:MM format')
|
|
677
|
-
.optional()
|
|
678
|
-
.openapi({
|
|
679
|
-
description: 'End time of the dismantling (HH:MM format). Defaults to 09:00',
|
|
680
|
-
example: '09:00'
|
|
681
|
-
}),
|
|
682
|
-
duration: z.number().positive().optional().openapi({
|
|
683
|
-
description: 'Duration of the dismantling in minutes. Defaults to 60',
|
|
684
|
-
example: 180
|
|
685
|
-
}),
|
|
686
|
-
phase_slot_id: z.number().int().positive().openapi({
|
|
687
|
-
description: 'ID of the associated phase slot',
|
|
688
|
-
example: 101
|
|
689
|
-
})
|
|
690
|
-
})
|
|
691
|
-
.openapi('UpsertPhaseSlotDismantling');
|
|
692
|
-
// ------------------------------
|
|
693
|
-
// Combined Phase Slot Schedules Schemas (Assembly + Dismantling)
|
|
694
|
-
// ------------------------------
|
|
695
|
-
export const phaseSlotScheduleOperationSchema = z
|
|
696
|
-
.object({
|
|
697
|
-
id: z.number().int().positive().optional().openapi({
|
|
698
|
-
description: 'Unique identifier for existing records (required for updates and deletes)',
|
|
699
|
-
example: 1
|
|
700
|
-
}),
|
|
701
|
-
start_time: z
|
|
702
|
-
.string()
|
|
703
|
-
.regex(/^\d{2}:\d{2}$/, 'Time must be in HH:MM format')
|
|
704
|
-
.optional()
|
|
569
|
+
.default('06:00')
|
|
705
570
|
.openapi({
|
|
706
571
|
description: 'Start time (HH:MM format)',
|
|
707
572
|
example: '06:00'
|
|
@@ -709,182 +574,183 @@ export const phaseSlotScheduleOperationSchema = z
|
|
|
709
574
|
end_time: z
|
|
710
575
|
.string()
|
|
711
576
|
.regex(/^\d{2}:\d{2}$/, 'Time must be in HH:MM format')
|
|
712
|
-
.
|
|
577
|
+
.default('09:00')
|
|
713
578
|
.openapi({
|
|
714
579
|
description: 'End time (HH:MM format)',
|
|
715
580
|
example: '09:00'
|
|
716
581
|
}),
|
|
717
|
-
duration: z.number().positive().
|
|
582
|
+
duration: z.number().positive().default(60).openapi({
|
|
718
583
|
description: 'Duration in minutes',
|
|
719
584
|
example: 180
|
|
720
585
|
}),
|
|
721
|
-
|
|
722
|
-
.
|
|
723
|
-
.regex(/^\d{4}-\d{2}-\d{2}$/, 'Date must be in YYYY-MM-DD format')
|
|
724
|
-
.optional()
|
|
586
|
+
phase_slot_schedule_type: z
|
|
587
|
+
.enum([PhaseSlotScheduleType.ASSEMBLY, PhaseSlotScheduleType.DISMANTLING])
|
|
725
588
|
.openapi({
|
|
726
|
-
description: '
|
|
727
|
-
example:
|
|
728
|
-
}),
|
|
729
|
-
_delete: z.boolean().optional().openapi({
|
|
730
|
-
description: 'Flag to mark this record for deletion. Requires existing id.',
|
|
731
|
-
example: false
|
|
589
|
+
description: 'Type of schedule',
|
|
590
|
+
example: PhaseSlotScheduleType.ASSEMBLY
|
|
732
591
|
})
|
|
733
592
|
})
|
|
734
|
-
.
|
|
735
|
-
|
|
736
|
-
if (data.value._delete === true && !data.value.id) {
|
|
737
|
-
data.issues.push({
|
|
738
|
-
code: 'custom',
|
|
739
|
-
message: 'ID is required when delete is true',
|
|
740
|
-
path: ['id'],
|
|
741
|
-
input: data.value
|
|
742
|
-
});
|
|
743
|
-
}
|
|
744
|
-
// If delete is false or undefined, date is required
|
|
745
|
-
if ((data.value._delete === false || data.value._delete === undefined) && !data.value.date) {
|
|
746
|
-
data.issues.push({
|
|
747
|
-
code: 'custom',
|
|
748
|
-
message: 'Date is required when delete is false or undefined',
|
|
749
|
-
path: ['date'],
|
|
750
|
-
input: data.value
|
|
751
|
-
});
|
|
752
|
-
}
|
|
753
|
-
})
|
|
754
|
-
.openapi('PhaseSlotScheduleOperation');
|
|
755
|
-
export const phaseSlotScheduleSchema = z
|
|
593
|
+
.openapi('UpsertPhaseSlotScheduleItem');
|
|
594
|
+
export const deletePhaseSlotScheduleItemSchema = z
|
|
756
595
|
.object({
|
|
757
|
-
|
|
758
|
-
description: 'ID of the
|
|
759
|
-
example:
|
|
760
|
-
}),
|
|
761
|
-
assembly: phaseSlotScheduleOperationSchema.openapi({
|
|
762
|
-
description: 'Assembly operation details with date'
|
|
763
|
-
}),
|
|
764
|
-
dismantling: phaseSlotScheduleOperationSchema.openapi({
|
|
765
|
-
description: 'Dismantling operation details with date'
|
|
596
|
+
id: z.number().int().positive().openapi({
|
|
597
|
+
description: 'ID of the schedule to delete',
|
|
598
|
+
example: 1
|
|
766
599
|
})
|
|
767
600
|
})
|
|
768
|
-
.openapi('
|
|
601
|
+
.openapi('DeletePhaseSlotScheduleItem');
|
|
769
602
|
export const upsertPhaseSlotSchedulesBodySchema = z
|
|
770
603
|
.object({
|
|
771
|
-
|
|
772
|
-
.array(
|
|
773
|
-
.
|
|
604
|
+
upsert: z
|
|
605
|
+
.array(upsertPhaseSlotScheduleItemSchema)
|
|
606
|
+
.optional()
|
|
774
607
|
.openapi({
|
|
775
|
-
description: 'Array of
|
|
608
|
+
description: 'Array of schedules to create or update',
|
|
776
609
|
example: [
|
|
777
610
|
{
|
|
778
611
|
phase_slot_id: 101,
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
},
|
|
785
|
-
dismantling: {
|
|
786
|
-
date: '2025-12-16',
|
|
787
|
-
start_time: '15:00',
|
|
788
|
-
end_time: '18:00',
|
|
789
|
-
duration: 180
|
|
790
|
-
}
|
|
791
|
-
},
|
|
792
|
-
{
|
|
793
|
-
phase_slot_id: 102,
|
|
794
|
-
assembly: {
|
|
795
|
-
id: 15,
|
|
796
|
-
_delete: true
|
|
797
|
-
}
|
|
612
|
+
date: '2025-12-15',
|
|
613
|
+
start_time: '06:00',
|
|
614
|
+
end_time: '09:00',
|
|
615
|
+
duration: 180,
|
|
616
|
+
phase_slot_schedule_type: 'assembly'
|
|
798
617
|
},
|
|
799
618
|
{
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
619
|
+
id: 5,
|
|
620
|
+
phase_slot_id: 101,
|
|
621
|
+
date: '2025-12-16',
|
|
622
|
+
start_time: '15:00',
|
|
623
|
+
end_time: '18:00',
|
|
624
|
+
duration: 180,
|
|
625
|
+
phase_slot_schedule_type: 'dismantling'
|
|
805
626
|
}
|
|
806
627
|
]
|
|
628
|
+
}),
|
|
629
|
+
delete: z
|
|
630
|
+
.array(deletePhaseSlotScheduleItemSchema)
|
|
631
|
+
.optional()
|
|
632
|
+
.openapi({
|
|
633
|
+
description: 'Array of schedule IDs to delete',
|
|
634
|
+
example: [{ id: 42 }]
|
|
807
635
|
})
|
|
636
|
+
})
|
|
637
|
+
.refine(data => (data.upsert && data.upsert.length > 0) || (data.delete && data.delete.length > 0), {
|
|
638
|
+
message: 'At least one upsert or delete operation is required'
|
|
808
639
|
})
|
|
809
640
|
.openapi('UpsertPhaseSlotSchedulesBody');
|
|
810
641
|
export const upsertPhaseSlotSchedulesDataSchema = z
|
|
811
642
|
.object({
|
|
812
|
-
|
|
813
|
-
description: 'Total number of schedules
|
|
814
|
-
example:
|
|
643
|
+
total_upserted: z.number().int().nonnegative().openapi({
|
|
644
|
+
description: 'Total number of schedules successfully upserted',
|
|
645
|
+
example: 3
|
|
815
646
|
}),
|
|
816
|
-
|
|
817
|
-
description: 'Total number of
|
|
818
|
-
example: 2
|
|
819
|
-
}),
|
|
820
|
-
total_dismantlings_upserted: z.number().int().nonnegative().openapi({
|
|
821
|
-
description: 'Total number of dismantlings successfully upserted',
|
|
647
|
+
total_deleted: z.number().int().nonnegative().openapi({
|
|
648
|
+
description: 'Total number of schedules successfully deleted',
|
|
822
649
|
example: 1
|
|
823
650
|
}),
|
|
824
|
-
|
|
825
|
-
description: '
|
|
826
|
-
example: 0
|
|
827
|
-
}),
|
|
828
|
-
total_dismantlings_deleted: z.number().int().nonnegative().openapi({
|
|
829
|
-
description: 'Total number of dismantlings successfully deleted',
|
|
830
|
-
example: 0
|
|
831
|
-
}),
|
|
832
|
-
upserted_assemblies: z.array(phaseSlotAssemblySchema).openapi({
|
|
833
|
-
description: 'Array of successfully upserted assemblies'
|
|
834
|
-
}),
|
|
835
|
-
upserted_dismantlings: z.array(phaseSlotDismantlingSchema).openapi({
|
|
836
|
-
description: 'Array of successfully upserted dismantlings'
|
|
837
|
-
}),
|
|
838
|
-
deleted_assemblies: z
|
|
839
|
-
.array(z.object({
|
|
840
|
-
id: z.number().int().positive(),
|
|
841
|
-
phase_slot_id: z.number().int().positive()
|
|
842
|
-
}))
|
|
843
|
-
.openapi({
|
|
844
|
-
description: 'Array of successfully deleted assemblies',
|
|
845
|
-
example: []
|
|
651
|
+
upserted_schedules: z.array(phaseSlotScheduleSchema).openapi({
|
|
652
|
+
description: 'Array of successfully upserted schedules'
|
|
846
653
|
}),
|
|
847
|
-
|
|
654
|
+
deleted_schedules: z
|
|
848
655
|
.array(z.object({
|
|
849
|
-
id: z.number().int().positive()
|
|
850
|
-
phase_slot_id: z.number().int().positive()
|
|
656
|
+
id: z.number().int().positive()
|
|
851
657
|
}))
|
|
852
658
|
.openapi({
|
|
853
|
-
description: 'Array of successfully deleted
|
|
854
|
-
example: []
|
|
659
|
+
description: 'Array of successfully deleted schedule IDs',
|
|
660
|
+
example: [{ id: 42 }]
|
|
855
661
|
}),
|
|
856
662
|
failed_operations: z
|
|
857
663
|
.array(z.object({
|
|
858
|
-
|
|
859
|
-
operation: z.enum(['assembly', 'dismantling']),
|
|
860
|
-
action: z.enum(['upsert', 'delete']),
|
|
664
|
+
operation: z.enum(['upsert', 'delete']),
|
|
861
665
|
error: z.string(),
|
|
862
|
-
data: z.union([
|
|
863
|
-
z.object({
|
|
864
|
-
id: z.number().int().positive().optional(),
|
|
865
|
-
date: z.string().optional(),
|
|
866
|
-
start_time: z.string().optional(),
|
|
867
|
-
end_time: z.string().optional(),
|
|
868
|
-
duration: z.number().positive().optional(),
|
|
869
|
-
_delete: z.boolean().optional()
|
|
870
|
-
}),
|
|
871
|
-
z.object({
|
|
872
|
-
id: z.number().int().positive()
|
|
873
|
-
})
|
|
874
|
-
])
|
|
666
|
+
data: z.union([upsertPhaseSlotScheduleItemSchema, deletePhaseSlotScheduleItemSchema])
|
|
875
667
|
}))
|
|
876
668
|
.openapi({
|
|
877
669
|
description: 'Array of operations that failed to process',
|
|
878
670
|
example: [
|
|
879
671
|
{
|
|
880
|
-
|
|
881
|
-
operation: 'assembly',
|
|
882
|
-
action: 'upsert',
|
|
672
|
+
operation: 'upsert',
|
|
883
673
|
error: 'Phase slot 999 not found or inactive',
|
|
884
|
-
data: {
|
|
674
|
+
data: {
|
|
675
|
+
phase_slot_id: 999,
|
|
676
|
+
date: '2025-12-15',
|
|
677
|
+
start_time: '06:00',
|
|
678
|
+
end_time: '09:00',
|
|
679
|
+
duration: 180,
|
|
680
|
+
phase_slot_schedule_type: 'assembly'
|
|
681
|
+
}
|
|
885
682
|
}
|
|
886
683
|
]
|
|
887
684
|
})
|
|
888
685
|
})
|
|
889
686
|
.openapi('UpsertPhaseSlotSchedulesData');
|
|
890
|
-
export const upsertPhaseSlotSchedulesResponseSchema = createMessageDataResponseSchema(upsertPhaseSlotSchedulesDataSchema, 'UpsertPhaseSlotSchedulesResponse', '
|
|
687
|
+
export const upsertPhaseSlotSchedulesResponseSchema = createMessageDataResponseSchema(upsertPhaseSlotSchedulesDataSchema, 'UpsertPhaseSlotSchedulesResponse', 'Phase slot schedules operation completed', 'Results of the upsert/delete operations');
|
|
688
|
+
// ------------------------------
|
|
689
|
+
// Check Slot Availability schemas
|
|
690
|
+
// ------------------------------
|
|
691
|
+
export const checkSlotAvailabilityQuerySchema = z
|
|
692
|
+
.object({
|
|
693
|
+
schedule_id: z
|
|
694
|
+
.string()
|
|
695
|
+
.min(1)
|
|
696
|
+
.transform(val => parseInt(val, 10))
|
|
697
|
+
.refine(val => !isNaN(val) && val > 0, {
|
|
698
|
+
message: 'Schedule ID must be a positive number'
|
|
699
|
+
})
|
|
700
|
+
.openapi({
|
|
701
|
+
description: 'The ID of the phase slot schedule',
|
|
702
|
+
example: '1'
|
|
703
|
+
}),
|
|
704
|
+
date: z
|
|
705
|
+
.string()
|
|
706
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/, 'Date must be in YYYY-MM-DD format')
|
|
707
|
+
.openapi({
|
|
708
|
+
description: 'The date to check availability (YYYY-MM-DD)',
|
|
709
|
+
example: '2025-12-15'
|
|
710
|
+
}),
|
|
711
|
+
start_time: z
|
|
712
|
+
.string()
|
|
713
|
+
.regex(/^\d{2}:\d{2}$/, 'Time must be in HH:MM format')
|
|
714
|
+
.openapi({
|
|
715
|
+
description: 'The start time to check availability (HH:MM)',
|
|
716
|
+
example: '08:00'
|
|
717
|
+
})
|
|
718
|
+
})
|
|
719
|
+
.openapi('CheckSlotAvailabilityQuery');
|
|
720
|
+
export const checkSlotAvailabilityDataSchema = z
|
|
721
|
+
.object({
|
|
722
|
+
schedule_id: z.number().openapi({
|
|
723
|
+
description: 'ID of the phase slot schedule',
|
|
724
|
+
example: 1
|
|
725
|
+
}),
|
|
726
|
+
date: z.string().openapi({
|
|
727
|
+
description: 'Date checked',
|
|
728
|
+
example: '2025-12-15'
|
|
729
|
+
}),
|
|
730
|
+
start_time: z.string().openapi({
|
|
731
|
+
description: 'Time slot checked',
|
|
732
|
+
example: '08:00'
|
|
733
|
+
}),
|
|
734
|
+
is_available: z.boolean().openapi({
|
|
735
|
+
description: 'Whether the slot is available for booking',
|
|
736
|
+
example: true
|
|
737
|
+
}),
|
|
738
|
+
max_capacity: z.number().openapi({
|
|
739
|
+
description: 'Maximum booking capacity',
|
|
740
|
+
example: 5
|
|
741
|
+
}),
|
|
742
|
+
current_bookings: z.number().openapi({
|
|
743
|
+
description: 'Current number of total bookings',
|
|
744
|
+
example: 3
|
|
745
|
+
}),
|
|
746
|
+
confirmed_bookings: z.number().openapi({
|
|
747
|
+
description: 'Current number of confirmed bookings',
|
|
748
|
+
example: 1
|
|
749
|
+
}),
|
|
750
|
+
available_capacity: z.number().openapi({
|
|
751
|
+
description: 'Remaining available capacity',
|
|
752
|
+
example: 2
|
|
753
|
+
})
|
|
754
|
+
})
|
|
755
|
+
.openapi('CheckSlotAvailabilityData');
|
|
756
|
+
export const checkSlotAvailabilityResponseSchema = createSuccessResponseSchema(checkSlotAvailabilityDataSchema, 'CheckSlotAvailabilityResponse', 'Slot availability information with capacity details');
|