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